diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml index 9f4a1223..368ad650 100644 --- a/.github/workflows/phpcs.yml +++ b/.github/workflows/phpcs.yml @@ -15,7 +15,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: '8.1' extensions: imagick, intl, mysql, bcmath, openssl ini-values: post_max_size=256M, short_open_tag=On tools: pecl, cs2pr, phpcs @@ -33,7 +33,7 @@ jobs: ${{ runner.os }}-php- - name: Install dependencies - run: composer install --prefer-dist --no-progress + run: composer install --prefer-dist --no-progress --no-suggest --ignore-platform-req=php # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" # Docs: https://getcomposer.org/doc/articles/scripts.md diff --git a/.gitignore b/.gitignore index ff7f293d..052dd34c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vendor/ composer.lock .idea/ +.phpcs* diff --git a/Module.php b/Module.php index e10e2b0c..35b0898d 100755 --- a/Module.php +++ b/Module.php @@ -1,17 +1,14 @@ -initRbac($e); - $eventManager->attach(MvcEvent::EVENT_ROUTE, array($this, 'checkRbac'), 0); - $eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'onDispatchError'), 0); - $eventManager->attach(MvcEvent::EVENT_RENDER_ERROR, array($this, 'onRenderError'), 0); + $eventManager->attach(MvcEvent::EVENT_ROUTE, [$this, 'checkRbac'], 0); + $eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, [$this, 'onDispatchError'], 0); + $eventManager->attach(MvcEvent::EVENT_RENDER_ERROR, [$this, 'onRenderError'], 0); } } @@ -55,51 +52,56 @@ public function getJsonModelError($e) { $error = $e->getError(); if (!$error) { - return; + return null; } $exception = $e->getParam('exception'); - $exceptionJson = array(); + $exceptionJson = []; if ($exception) { - $exceptionJson = array( - 'class' => get_class($exception), + $exceptionJson = [ + 'class' => \get_class($exception), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'message' => $exception->getMessage(), - 'stacktrace' => $exception->getTraceAsString() - ); + 'stacktrace' => $exception->getTraceAsString(), + ]; if ($exception->getCode() >= 400 && $exception->getCode() < 600) { $e->getResponse()->setStatusCode($exception->getCode()); } } - $errorJson = array( - 'message' => $exception - ? $exception->getMessage() : 'An error occurred during execution; please try again later.', - 'error' => $error, + $errorJson = [ + 'message' => $exception + ? $exception->getMessage() + : 'An error occurred during execution; please try again later.', + 'error' => $error, 'exception' => $exceptionJson, - ); + ]; if ($error === 'error-router-no-match') { $errorJson['message'] = 'Resource not found.'; } - $model = new JsonModel(array('errors' => array($errorJson))); + + if ($exception && $exception->getCode() === 400) { + $model = new JsonModel([ + 'errors' => [json_decode($exception->getMessage(), true, 512, JSON_THROW_ON_ERROR)], + ]); + } else { + $model = new JsonModel(['errors' => [$errorJson]]); + } + $e->setResult($model); + return $model; } - /** - * init Rbac - * - * @param MvcEvent $e - */ - public function initRbac(MvcEvent $e) + public function initRbac(MvcEvent $mvcEvent) { - $sm = $e->getApplication()->getServiceManager(); + $sm = $mvcEvent->getApplication()->getServiceManager(); $config = $sm->get('Config'); - $globalPermissions = isset($config['permissions']) ? $config['permissions'] : []; + $globalPermissions = $config['permissions'] ?? []; - $rolesPermissions = isset($config['roles']) ? $config['roles'] : []; + $rolesPermissions = $config['roles'] ?? []; $rbac = new Rbac(); foreach ($rolesPermissions as $role => $permissions) { @@ -132,186 +134,36 @@ public function initRbac(MvcEvent $e) $rbac->addRole($role); //setting to view - $e->getViewModel()->rbac = $rbac; + $mvcEvent->getViewModel()->rbac = $rbac; } /** - * Check Rbac + * @param MvcEvent $mvcEvent * - * @param MvcEvent $e - * @return \Laminas\Stdlib\ResponseInterface + * @return ResponseInterface|void */ - public function checkRbac(MvcEvent $e) + public function checkRbac(MvcEvent $mvcEvent) { - $route = $e->getRouteMatch()->getMatchedRouteName(); - $sm = $e->getApplication()->getServiceManager(); + $route = $mvcEvent->getRouteMatch()->getMatchedRouteName(); + $serviceManager = $mvcEvent->getApplication()->getServiceManager(); /** @var ConnectedUserService $connectedUserService */ - $connectedUserService = $sm->get(ConnectedUserService::class); + $connectedUserService = $serviceManager->get(ConnectedUserService::class); $connectedUser = $connectedUserService->getConnectedUser(); $roles[] = 'guest'; if ($connectedUser !== null) { - $roles = $connectedUser->getRoles(); + $roles = $connectedUser->getRolesArray(); } - $isGranted = false; foreach ($roles as $role) { - if ($e->getViewModel()->rbac->isGranted($role, $route)) { - $id = (int)$e->getRouteMatch()->getParam('id'); - if (($route === 'monarc_api_client_anr' && !empty($id)) - || strncmp($route, 'monarc_api_global_client_anr/', 29) === 0 - ) { - if ($route === 'monarc_api_client_anr') { - $anrid = $id; - } else { - $anrid = (int)$e->getRouteMatch()->getParam('anrid'); - } - if (empty($anrid)) { - break; - } - - $result = $this->validateAnrStatusAndGetResponseIfInvalid($anrid, $e, $route); - if ($result !== null) { - return $result; - } - - $lk = current($sm->get(UserAnrTable::class)->getEntityByFields( - ['anr' => $anrid, 'user' => $connectedUser->getId()] - )); - if (empty($lk)) { - // On doit tester si c'est un snapshot, dans ce cas, on autorise l'accès mais en READ-ONLY - if ($e->getRequest()->getMethod() !== Request::METHOD_GET - && !$this->authorizedPost($route, $e->getRequest()->getMethod()) - ) { - break; // même si c'est un snapshot, on n'autorise que du GET - } - $snap = current($sm->get(SnapshotTable::class)->getEntityByFields(['anr' => $anrid])); - if (empty($snap)) { - break; // ce n'est pas un snapshot - } - $lk = current($sm->get(UserAnrTable::class)->getEntityByFields( - ['anr' => $snap->get('anrReference')->get('id'), 'user' => $connectedUser->getId()] - )); - if (empty($lk)) { - break; // l'user n'avait de toute façon pas accès à l'anr dont est issue ce snapshot - } - $isGranted = true; - break; - } - - if ($lk->get('rwd') === 0 && $e->getRequest()->getMethod() !== Request::METHOD_GET) { - if ($this->authorizedPost($route, $e->getRequest()->getMethod())) { - // on autorise les POST pour les export - $isGranted = true; - } - break; // les droits ne sont pas bon - } - } - - $isGranted = true; - break; - } - } - - if (!$isGranted) { - $response = $e->getResponse(); - $response->setStatusCode($connectedUser === null ? 401 : 403); - - return $response; - } - } - - private function authorizedPost($route, $method) - { - return $method === 'POST' && - ($route === 'monarc_api_global_client_anr/export' || // export ANR - $route === 'monarc_api_global_client_anr/instance_export' || // export Instance - $route === 'monarc_api_global_client_anr/objects_export' || // export Object - $route === 'monarc_api_global_client_anr/deliverable'); // generate a report - } - - /** - * Validates the anr status for NON GET method requests exclude DELETE (cancellation of background import). - */ - private function validateAnrStatusAndGetResponseIfInvalid( - int $anrId, - MvcEvent $e, - string $route - ): ?ResponseInterface { - /* GET requests are always allowed and cancellation of import (delete import process -> PID). */ - if ($e->getRequest()->getMethod() === Request::METHOD_GET - || ( - $e->getRequest()->getMethod() === Request::METHOD_DELETE - && $route === 'monarc_api_global_client_anr/instance_import' - ) - ) { - return null; - } - - $sm = $e->getApplication()->getServiceManager(); - - /** @var Anr $anr */ - $anr = $sm->get(AnrTable::class)->findById($anrId); - if ($anr->isActive()) { - return null; - } - - /* Allow deleting anr if the status is waiting for import or there is an import error. */ - if ($route === 'monarc_api_client_anr' - && $e->getRequest()->getMethod() === Request::METHOD_DELETE - && ($anr->getStatus() === AnrSuperClass::STATUS_IMPORT_ERROR - || $anr->getStatus() === AnrSuperClass::STATUS_AWAITING_OF_IMPORT - ) - ) { - return null; - } - - /* Allow to restore a snapshot if there is an import error. */ - if ($route === 'monarc_api_global_client_anr/snapshot_restore' - && $anr->getStatus() === AnrSuperClass::STATUS_IMPORT_ERROR - && $e->getRequest()->getMethod() === Request::METHOD_POST - ) { - return null; - } - - $result = [ - 'status' => $anr->getStatusName(), - 'importStatus' => [], - ]; - /** @var CronTaskService $cronTaskService */ - $cronTaskService = $sm->get(CronTaskService::class); - - if ($anr->getStatus() === AnrSuperClass::STATUS_UNDER_IMPORT) { - $importCronTask = $cronTaskService->getLatestTaskByNameWithParam( - CronTask::NAME_INSTANCE_IMPORT, - ['anrId' => $anrId] - ); - if ($importCronTask !== null && $importCronTask->getStatus() === CronTask::STATUS_IN_PROGRESS) { - /** @var InstanceTable $instanceTable */ - $instanceTable = $sm->get(InstanceTable::class); - $timeDiff = $importCronTask->getUpdatedAt()->diff(new DateTime()); - $instancesNumber = $instanceTable->countByAnrIdFromDate($anrId, $importCronTask->getUpdatedAt()); - $result['importStatus'] = [ - 'executionTime' => $timeDiff->h . ' hours ' . $timeDiff->i . ' min ' . $timeDiff->s . ' sec', - 'createdInstances' => $instancesNumber, - ]; - } - } elseif ($anr->getStatus() === AnrSuperClass::STATUS_IMPORT_ERROR) { - $importCronTask = $cronTaskService->getLatestTaskByNameWithParam( - CronTask::NAME_INSTANCE_IMPORT, - ['anrId' => $anrId] - ); - if ($importCronTask !== null && $importCronTask->getStatus() === CronTask::STATUS_FAILURE) { - $result['importStatus'] = [ - 'errorMessage' => $importCronTask->getResultMessage(), - ]; + if ($mvcEvent->getViewModel()->rbac->isGranted($role, $route)) { + return; } } - $response = $e->getResponse(); - $response->setContent(json_encode($result, JSON_THROW_ON_ERROR)); - $response->setStatusCode(409); + $response = $mvcEvent->getResponse(); + $response->setStatusCode($connectedUser === null ? 401 : 403); return $response; } diff --git a/README.md b/README.md index b703c15a..d56b3469 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,28 @@ +MONARC client project +===================== + +Objective +--------- + +The backend part of the FrontOffice tool. It provides all the api endpoints to server the frontend calls with the json data. +The export/import functionality as wells as statistics aggregation is the other side of the functionality of the project. +It is dependent on the zm-core projects. + + +Middleware +---------- + +There is a AnrValidationMiddleware that is processed before the controllers actions and performs the anr access validation and some related endpoints access. +In case if the middleware validations passed successfully the anr object is added to the attribute of the request and can be accessible across all the /client-anr based controllers/actions. License ------- This software is licensed under [GNU Affero General Public License version 3](http://www.gnu.org/licenses/agpl-3.0.html) -Copyright (C) 2016-2020 SMILE gie securitymadein.lu +- Copyright (C) 2022-2024 Luxembourg House of Cybersecurity https://lhc.lu +- Copyright (C) 2016-2022 SMILE gie securitymadein.lu +- Copyright (C) 2016-2024 Jérôme Lombardi - https://github.com/jerolomb +- Copyright (C) 2016-2024 Juan Rocha - https://github.com/jfrocha +- Copyright (C) 2017-2024 Cédric Bonhomme - https://www.cedricbonhomme.org +- Copyright (C) 2019-2024 Ruslan Baidan - https://github.com/ruslanbaidan diff --git a/composer.json b/composer.json index b18151a7..334683b0 100755 --- a/composer.json +++ b/composer.json @@ -41,24 +41,27 @@ } ], "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "ext-intl": "*", + "ext-imagick": "*", "ext-json": "*", "ext-bcmath": "*", "ext-openssl": "*", "ext-posix": "*", "doctrine/doctrine-orm-module": "^5.1", - "monarc/core": "^2.12.6", + "monarc/core": "dev-feature/remove-db-abstract as v2.12.7", "robmorgan/phinx": "^0.13.4", "laminas/laminas-di": "^3.1", "laminas/laminas-mvc": "^3.1", + "laminas/laminas-mvc-console": "^1.2", "laminas/laminas-permissions-rbac": "^3.0", "laminas/laminas-filter": "^2.9", "laminas/laminas-inputfilter": "^2.10", "laminas/laminas-dependency-plugin": "^2.0", "symfony/console": "^5.0", "guzzlehttp/guzzle": "^6.5", - "phpoffice/phpword": "^0.18.1" + "phpoffice/phpword": "^0.18.1", + "laminas/laminas-mvc-middleware": "^2.2" }, "require-dev": { "roave/security-advisories": "dev-master" diff --git a/config/module.config.php b/config/module.config.php index 204673d1..d793b50b 100755 --- a/config/module.config.php +++ b/config/module.config.php @@ -1,38 +1,46 @@ - [ @@ -50,55 +58,55 @@ ], ], - 'monarc_api_admin_users_rights' => [ + 'monarc_api_admin_users' => [ 'type' => 'segment', 'options' => [ - 'route' => '/api/users-rights[/:id]', + 'route' => '/api/users[/:id]', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAdminUsersRightsController::class, + 'controller' => Controller\ApiAdminUsersController::class, ], ], ], - 'monarc_api_admin_users' => [ + 'monarc_api_admin_user_reset_password' => [ 'type' => 'segment', 'options' => [ - 'route' => '/api/users[/:id]', + 'route' => '/api/users/:id/resetPassword', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ 'controller' => Controller\ApiAdminUsersController::class, + 'action' => 'resetPassword', ], ], ], - 'monarc_api_admin_user_reset_password' => [ + 'monarc_api_client' => [ 'type' => 'segment', 'options' => [ - 'route' => '/api/users/:id/resetPassword', + 'route' => '/api/client[/:id]', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAdminUsersController::class, - 'action' => 'resetPassword' + 'controller' => Controller\ApiClientsController::class, ], ], ], - 'monarc_api_client' => [ + 'monarc_api_system_messages' => [ 'type' => 'segment', 'options' => [ - 'route' => '/api/client[/:id]', + 'route' => '/api/system-messages[/:id]', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiClientsController::class, + 'controller' => Controller\ApiSystemMessagesController::class, ], ], ], @@ -119,12 +127,9 @@ 'monarc_api_referentials' => [ 'type' => 'segment', 'options' => [ - 'route' => '/api/referentials[/:id]', - 'constraints' => [ - 'id' => '[0-9]+', - ], + 'route' => '/api/referentials', 'defaults' => [ - 'controller' => Controller\ApiReferentialsController::class, + 'controller' => Controller\ApiCoreReferentialsController::class, ], ], ], @@ -134,7 +139,11 @@ 'options' => [ 'route' => '/api/client-duplicate-anr', 'defaults' => [ - 'controller' => Controller\ApiDuplicateAnrController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiDuplicateAnrController::class, + ), ], ], ], @@ -178,7 +187,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrController::class, + ), ], ], ], @@ -191,7 +204,8 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiGuidesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec(Controller\ApiGuidesController::class), ], ], ], @@ -204,7 +218,8 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiGuidesItemsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec(Controller\ApiGuidesItemsController::class), ], ], ], @@ -224,7 +239,11 @@ 'options' => [ 'route' => 'export', 'defaults' => [ - 'controller' => Controller\ApiAnrExportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Export\Controller\ApiAnrExportController::class, + ), ], ], ], @@ -237,7 +256,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrAssetsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrAssetsController::class, + ), ], ], ], @@ -249,7 +272,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrAmvsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrAmvsController::class, + ), ], ], ], @@ -261,7 +288,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrReferentialsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrReferentialsController::class, + ), ], ], ], @@ -273,7 +304,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrMeasuresController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrMeasuresController::class, + ), ], ], ], @@ -285,7 +320,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrMeasuresMeasuresController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrMeasuresLinksController::class, + ), ], ], ], @@ -297,7 +336,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrThreatsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrThreatsController::class, + ), ], ], ], @@ -309,7 +352,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrThemesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrThemesController::class, + ), ], ], ], @@ -321,7 +368,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrVulnerabilitiesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrVulnerabilitiesController::class, + ), ], ], ], @@ -333,7 +384,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRolfTagsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRolfTagsController::class, + ), ], ], ], @@ -345,7 +400,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRolfRisksController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRolfRisksController::class, + ), ], ], ], @@ -357,7 +416,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrObjectsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrObjectsController::class, + ), ], ], ], @@ -369,7 +432,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrObjectController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrObjectsController::class, + ), 'action' => 'parents' ], ], @@ -382,7 +449,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrObjectsExportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Export\Controller\ApiAnrObjectsExportController::class, + ), ], ], ], @@ -394,7 +465,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrObjectsImportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Import\Controller\ApiAnrObjectsImportController::class, + ), ], ], ], @@ -406,7 +481,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrInterviewsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrInterviewsController::class, + ), ], ], ], @@ -418,7 +497,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrScalesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrScalesController::class, + ), ], ], ], @@ -430,7 +513,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiOperationalRisksScalesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiOperationalRisksScalesController::class, + ), ], ], ], @@ -439,11 +526,15 @@ 'options' => [ 'route' => 'operational-scales/:scaleid/comments[/:id]', 'constraints' => [ - 'id' => '[0-9]+', 'scaleid' => '[0-9]+', + 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiOperationalRisksScalesCommentsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiOperationalRisksScalesCommentsController::class, + ), ], ], ], @@ -455,7 +546,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrScalesTypesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrScalesTypesController::class, + ), ], ], ], @@ -468,7 +563,11 @@ 'scaleid' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrScalesCommentsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrScalesCommentsController::class, + ), ], ], ], @@ -480,7 +579,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrQuestionsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrQuestionsController::class, + ), ], ], ], @@ -492,67 +595,91 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrQuestionsChoicesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrQuestionsChoicesController::class, + ), ], ], ], - 'recommandations' => [ + 'recommendations' => [ 'type' => 'segment', 'options' => [ - 'route' => 'recommandations[/:id]', + 'route' => 'recommendations[/:id]', 'constraints' => [ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecommandationsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecommendationsController::class, + ), ], ], ], - 'recommandations_historics' => [ + 'recommendations_history' => [ 'type' => 'segment', 'options' => [ - 'route' => 'recommandations-historics[/:id]', + 'route' => 'recommendations-history[/:id]', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecommandationsHistoricsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecommendationsHistoryController::class, + ), ], ], ], - 'recommandations_risks' => [ + 'recommendations_risks' => [ 'type' => 'segment', 'options' => [ - 'route' => 'recommandations-risks[/:id]', + 'route' => 'recommendations-risks[/:id]', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecommandationsRisksController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecommendationsRisksController::class, + ), ], ], ], - 'recommandations_risks_validate' => [ + 'recommendations_risks_validate' => [ 'type' => 'segment', 'options' => [ - 'route' => 'recommandations-risks[/:id]/validate', + 'route' => 'recommendations-risks[/:id]/validate', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecommandationsRisksValidateController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecommendationsRisksValidateController::class, + ), ], ], ], - 'recommandations_sets' => [ + 'recommendations_sets' => [ 'type' => 'segment', 'options' => [ - 'route' => 'recommandations-sets[/:id]', + 'route' => 'recommendations-sets[/:id]', 'constraints' => [ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecommandationsSetsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecommendationsSetsController::class, + ), ], ], ], @@ -564,7 +691,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordsController::class, + ), ], ], ], @@ -576,7 +707,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordActorsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordActorsController::class, + ), ], ], ], @@ -585,7 +720,11 @@ 'options' => [ 'route' => 'record-data-categories', 'defaults' => [ - 'controller' => Controller\ApiAnrRecordDataCategoriesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordDataCategoriesController::class, + ), ], ], ], @@ -597,7 +736,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordInternationalTransfersController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordInternationalTransfersController::class, + ), ], ], ], @@ -609,7 +752,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordPersonalDataController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordPersonalDataController::class, + ), ], ], ], @@ -621,7 +768,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordProcessorsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordProcessorsController::class, + ), ], ], ], @@ -633,7 +784,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordRecipientsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordRecipientsController::class, + ), ], ], ], @@ -645,7 +800,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRecordsExportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordsExportController::class, + ), ], ], ], @@ -654,7 +813,11 @@ 'options' => [ 'route' => 'records/export', 'defaults' => [ - 'controller' => Controller\ApiAnrRecordsExportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordsExportController::class, + ), ], ], ], @@ -663,7 +826,11 @@ 'options' => [ 'route' => 'records/import', 'defaults' => [ - 'controller' => Controller\ApiAnrRecordsImportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordsImportController::class, + ), ], ], ], @@ -672,7 +839,11 @@ 'options' => [ 'route' => 'records/duplicate', 'defaults' => [ - 'controller' => Controller\ApiAnrRecordDuplicateController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRecordDuplicateController::class, + ), ], ], ], @@ -684,8 +855,11 @@ 'type' => 'all|real|targeted', ], 'defaults' => [ - 'controller' => Controller\ApiDashboardAnrCartoRisksController::class, - 'type' => 'all', + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiDashboardAnrCartoRisksController::class, + ), ], ], ], @@ -697,7 +871,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRiskOwnersController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRiskOwnersController::class, + ), ], ], ], @@ -709,7 +887,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRisksController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRisksController::class, + ), ], ], ], @@ -718,7 +900,11 @@ 'options' => [ 'route' => 'risks-dashboard[/:id]', 'defaults' => [ - 'controller' => Controller\ApiDashboardAnrRisksController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiDashboardAnrRisksController::class, + ), ], ], ], @@ -730,7 +916,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrRisksOpController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrRisksOpController::class, + ), ], ], ], @@ -742,19 +932,11 @@ 'id' => '[a-f0-9-]*', ], 'defaults' => [ - 'controller' => Controller\ApiAnrLibraryController::class, - ], - ], - ], - 'library_category' => [ - 'type' => 'segment', - 'options' => [ - 'route' => 'library-category[/:id]', - 'constraints' => [ - 'id' => '[0-9]+', - ], - 'defaults' => [ - 'controller' => Controller\ApiAnrLibraryCategoryController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrLibraryController::class, + ), ], ], ], @@ -766,7 +948,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrTreatmentPlanController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrTreatmentPlanController::class, + ), ], ], ], @@ -778,7 +964,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiSoaController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiSoaController::class, + ), ], ], ], @@ -790,7 +980,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiSoaCategoryController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiSoaCategoryController::class, + ), ], ], ], @@ -802,7 +996,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrInstancesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrInstancesController::class, + ), ], ], ], @@ -814,7 +1012,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrInstancesExportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Export\Controller\ApiAnrInstancesExportController::class, + ), ], ], ], @@ -824,7 +1026,11 @@ 'route' => 'instances/import', 'constraints' => [], 'defaults' => [ - 'controller' => Import\Controller\ApiAnrInstancesImportController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Import\Controller\ApiAnrInstancesImportController::class, + ), ], ], ], @@ -836,7 +1042,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrInstancesRisksController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrInstancesRisksController::class, + ), ], ], ], @@ -848,7 +1058,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrInstancesRisksOpController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrInstancesRisksOpController::class, + ), ], ], ], @@ -860,7 +1074,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrInstancesConsequencesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrInstancesConsequencesController::class, + ), ], ], ], @@ -872,32 +1090,44 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiSoaScaleCommentController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiSoaScaleCommentController::class, + ), ], ], ], - 'anr_metadatas_on_instances' => [ + 'anr_instance_metadata_field' => [ 'type' => 'segment', 'options' => [ - 'route' => 'metadatas-on-instances[/:id]', + 'route' => 'anr-instances-metadata-fields[/:id]', 'constraints' => [ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrMetadatasOnInstancesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrInstancesMetadataFieldsController::class, + ), ], ], ], 'instance_metadata' => [ 'type' => 'segment', 'options' => [ - 'route' => 'instances/:instanceid/instances_metadatas[/:id]', + 'route' => 'instances/:instanceid/metadata[/:id]', 'constraints' => [ 'instanceid' => '[0-9]+', 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiInstanceMetadataController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiInstanceMetadataController::class, + ), ], ], ], @@ -909,7 +1139,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrObjectsCategoriesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrObjectsCategoriesController::class, + ), ], ], ], @@ -921,7 +1155,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiSnapshotController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiSnapshotController::class, + ), ], ], ], @@ -933,7 +1171,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiSnapshotRestoreController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiSnapshotRestoreController::class, + ), ], ], ], @@ -945,7 +1187,11 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiAnrDeliverableController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrDeliverableController::class, + ), ], ], ], @@ -954,7 +1200,11 @@ 'options' => [ 'route' => 'objects-objects[/:id]', 'defaults' => [ - 'controller' => Controller\ApiAnrObjectsObjectsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrObjectsObjectsController::class, + ), ], ], ], @@ -963,7 +1213,11 @@ 'options' => [ 'route' => 'objects-duplication', 'defaults' => [ - 'controller' => Controller\ApiAnrObjectsDuplicationController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec( + AnrValidationMiddleware::class, + Controller\ApiAnrObjectsDuplicationController::class, + ), ], ], ], @@ -977,7 +1231,8 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiDeliveriesModelsController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec(Controller\ApiDeliveriesModelsController::class), ], ], ], @@ -1001,7 +1256,8 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiUserTwoFAController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec(Controller\ApiUserTwoFAController::class), ], ], ], @@ -1013,7 +1269,8 @@ 'id' => '[0-9]+', ], 'defaults' => [ - 'controller' => Controller\ApiUserRecoveryCodesController::class, + 'controller' => PipeSpec::class, + 'middleware' => new PipeSpec(Controller\ApiUserRecoveryCodesController::class), ], ], ], @@ -1036,7 +1293,7 @@ 'route' => '/api/stats[/]', 'verb' => 'get', 'defaults' => [ - 'controller' => StatsController::class, + 'controller' => Stats\Controller\StatsController::class, ], ], ], @@ -1053,7 +1310,7 @@ 'route' => 'processed[/]', 'verb' => 'get', 'defaults' => [ - 'controller' => StatsController::class, + 'controller' => Stats\Controller\StatsController::class, 'action' => 'getProcessedList' ], ], @@ -1064,7 +1321,7 @@ 'route' => 'anrs-settings[/]', 'verb' => 'get,patch', 'defaults' => [ - 'controller' => StatsAnrsSettingsController::class, + 'controller' => Stats\Controller\StatsAnrsSettingsController::class, ], ], ], @@ -1074,7 +1331,7 @@ 'route' => 'general-settings[/]', 'verb' => 'get,patch', 'defaults' => [ - 'controller' => StatsGeneralSettingsController::class, + 'controller' => Stats\Controller\StatsGeneralSettingsController::class, ], ], ], @@ -1084,7 +1341,7 @@ 'route' => 'validate-stats-availability[/]', 'verb' => 'get', 'defaults' => [ - 'controller' => StatsController::class, + 'controller' => Stats\Controller\StatsController::class, 'action' => 'validateStatsAvailability' ], ], @@ -1096,111 +1353,88 @@ 'controllers' => [ 'factories' => [ + Controller\ApiGuidesController::class => AutowireFactory::class, + Controller\ApiGuidesItemsController::class => AutowireFactory::class, + Controller\ApiModelsController::class => AutowireFactory::class, + Controller\ApiDuplicateAnrController::class => AutowireFactory::class, + Controller\ApiAnrReferentialsController::class => AutowireFactory::class, + Controller\ApiAnrMeasuresController::class => AutowireFactory::class, + Controller\ApiAnrMeasuresLinksController::class => AutowireFactory::class, + Controller\ApiAnrQuestionsController::class => AutowireFactory::class, + Controller\ApiAnrQuestionsChoicesController::class => AutowireFactory::class, + Controller\ApiAnrRolfTagsController::class => AutowireFactory::class, + Controller\ApiAnrRolfRisksController::class => AutowireFactory::class, + Controller\ApiAnrInterviewsController::class => AutowireFactory::class, + Controller\ApiAnrRecordActorsController::class => AutowireFactory::class, + Controller\ApiAnrRecordDuplicateController::class => AutowireFactory::class, + Controller\ApiAnrRecordDataCategoriesController::class => AutowireFactory::class, + Controller\ApiAnrRecordInternationalTransfersController::class => AutowireFactory::class, + Controller\ApiAnrRecordPersonalDataController::class => AutowireFactory::class, + Controller\ApiAnrRecordProcessorsController::class => AutowireFactory::class, + Controller\ApiAnrRecordRecipientsController::class => AutowireFactory::class, + Controller\ApiAnrRecordsController::class => AutowireFactory::class, + Controller\ApiAnrRecordsExportController::class => AutowireFactory::class, + Controller\ApiSoaCategoryController::class => AutowireFactory::class, + Controller\ApiDashboardAnrCartoRisksController::class => AutowireFactory::class, + Controller\ApiDeliveriesModelsController::class => AutowireFactory::class, + Controller\ApiAnrTreatmentPlanController::class => AutowireFactory::class, + Controller\ApiAnrRecommendationsController::class => AutowireFactory::class, + Controller\ApiAnrRecommendationsHistoryController::class => AutowireFactory::class, + Controller\ApiAnrRecommendationsRisksController::class => AutowireFactory::class, + Controller\ApiAnrRecommendationsRisksValidateController::class => AutowireFactory::class, + Controller\ApiAnrRecommendationsSetsController::class => AutowireFactory::class, + Controller\ApiSnapshotRestoreController::class => AutowireFactory::class, Controller\ApiAdminPasswordsController::class => AutowireFactory::class, Controller\ApiAdminUsersController::class => AutowireFactory::class, Controller\ApiAdminUsersRolesController::class => AutowireFactory::class, - Controller\ApiAdminUsersRightsController::class => Controller\ApiAdminUsersRightsControllerFactory::class, - Controller\ApiAnrController::class => Controller\ApiAnrControllerFactory::class, - Controller\ApiGuidesController::class => Controller\ApiGuidesControllerFactory::class, - Controller\ApiGuidesItemsController::class => Controller\ApiGuidesItemsControllerFactory::class, - Controller\ApiSnapshotController::class => Controller\ApiSnapshotControllerFactory::class, - Controller\ApiSnapshotRestoreController::class => Controller\ApiSnapshotRestoreControllerFactory::class, + Controller\ApiAnrController::class => AutowireFactory::class, Controller\ApiConfigController::class => AutowireFactory::class, Controller\ApiClientsController::class => AutowireFactory::class, - Controller\ApiModelsController::class => Controller\ApiModelsControllerFactory::class, - Controller\ApiReferentialsController::class => AutowireFactory::class, - Controller\ApiDuplicateAnrController::class => Controller\ApiDuplicateAnrControllerFactory::class, + Controller\ApiCoreReferentialsController::class => AutowireFactory::class, Controller\ApiUserPasswordController::class => AutowireFactory::class, Controller\ApiUserTwoFAController::class => AutowireFactory::class, Controller\ApiUserRecoveryCodesController::class => AutowireFactory::class, Controller\ApiUserProfileController::class => AutowireFactory::class, - Controller\ApiAnrAssetsController::class => Controller\ApiAnrAssetsControllerFactory::class, - Controller\ApiAnrAmvsController::class => Controller\ApiAnrAmvsControllerFactory::class, - Controller\ApiAnrReferentialsController::class => Controller\ApiAnrReferentialsControllerFactory::class, - Controller\ApiAnrMeasuresController::class => Controller\ApiAnrMeasuresControllerFactory::class, - Controller\ApiAnrMeasuresMeasuresController::class - => Controller\ApiAnrMeasuresMeasuresControllerFactory::class, - Controller\ApiAnrObjectsController::class => Controller\ApiAnrObjectsControllerFactory::class, - Controller\ApiAnrObjectsObjectsController::class => Controller\ApiAnrObjectsObjectsControllerFactory::class, - Controller\ApiAnrObjectsDuplicationController::class - => Controller\ApiAnrObjectsDuplicationControllerFactory::class, - Controller\ApiAnrObjectController::class => Controller\ApiAnrObjectControllerFactory::class, - Controller\ApiAnrQuestionsController::class => Controller\ApiAnrQuestionsControllerFactory::class, - Controller\ApiAnrQuestionsChoicesController::class - => Controller\ApiAnrQuestionsChoicesControllerFactory::class, - Controller\ApiAnrThreatsController::class => Controller\ApiAnrThreatsControllerFactory::class, - Controller\ApiAnrThemesController::class => Controller\ApiAnrThemesControllerFactory::class, - Controller\ApiAnrVulnerabilitiesController::class - => Controller\ApiAnrVulnerabilitiesControllerFactory::class, - Controller\ApiAnrRolfTagsController::class => Controller\ApiAnrRolfTagsControllerFactory::class, - Controller\ApiAnrRolfRisksController::class => Controller\ApiAnrRolfRisksControllerFactory::class, - Controller\ApiAnrInterviewsController::class => Controller\ApiAnrInterviewsControllerFactory::class, - Controller\ApiAnrRecommandationsController::class - => Controller\ApiAnrRecommandationsControllerFactory::class, - Controller\ApiAnrRecommandationsHistoricsController::class - => Controller\ApiAnrRecommandationsHistoricsControllerFactory::class, - Controller\ApiAnrRecommandationsRisksController::class - => Controller\ApiAnrRecommandationsRisksControllerFactory::class, - Controller\ApiAnrRecommandationsRisksValidateController::class - => Controller\ApiAnrRecommandationsRisksValidateControllerFactory::class, - Controller\ApiAnrRecommandationsSetsController::class - => Controller\ApiAnrRecommandationsSetsControllerFactory::class, - Controller\ApiAnrRecordActorsController::class => Controller\ApiAnrRecordActorsControllerFactory::class, - Controller\ApiAnrRecordDuplicateController::class - => Controller\ApiAnrRecordDuplicateControllerFactory::class, - Controller\ApiAnrRecordDataCategoriesController::class - => Controller\ApiAnrRecordDataCategoriesControllerFactory::class, - Controller\ApiAnrRecordInternationalTransfersController::class - => Controller\ApiAnrRecordInternationalTransfersControllerFactory::class, - Controller\ApiAnrRecordPersonalDataController::class - => Controller\ApiAnrRecordPersonalDataControllerFactory::class, - Controller\ApiAnrRecordProcessorsController::class - => Controller\ApiAnrRecordProcessorsControllerFactory::class, - Controller\ApiAnrRecordRecipientsController::class - => Controller\ApiAnrRecordRecipientsControllerFactory::class, - Controller\ApiAnrRecordsController::class => Controller\ApiAnrRecordsControllerFactory::class, - Controller\ApiAnrRecordsExportController::class => Controller\ApiAnrRecordsExportControllerFactory::class, + Controller\ApiAnrAssetsController::class => AutowireFactory::class, + Controller\ApiAnrAmvsController::class => AutowireFactory::class, + Controller\ApiAnrObjectsController::class => AutowireFactory::class, + Controller\ApiAnrObjectsObjectsController::class => AutowireFactory::class, + Controller\ApiAnrObjectsDuplicationController::class => AutowireFactory::class, + Controller\ApiAnrThreatsController::class => AutowireFactory::class, + Controller\ApiAnrThemesController::class => AutowireFactory::class, + Controller\ApiAnrVulnerabilitiesController::class => AutowireFactory::class, Controller\ApiAnrRecordsImportController::class => AutowireFactory::class, - Controller\ApiAnrTreatmentPlanController::class => Controller\ApiAnrTreatmentPlanControllerFactory::class, Controller\ApiSoaController::class => AutowireFactory::class, - Controller\ApiSoaCategoryController::class => Controller\ApiSoaCategoryControllerFactory::class, - Controller\ApiAnrScalesController::class => Controller\ApiAnrScalesControllerFactory::class, - Controller\ApiAnrScalesTypesController::class => Controller\ApiAnrScalesTypesControllerFactory::class, - Controller\ApiAnrScalesCommentsController::class => Controller\ApiAnrScalesCommentsControllerFactory::class, - Controller\ApiDashboardAnrCartoRisksController::class - => Controller\ApiDashboardAnrCartoRisksControllerFactory::class, + Controller\ApiAnrScalesController::class => AutowireFactory::class, + Controller\ApiAnrScalesTypesController::class => AutowireFactory::class, + Controller\ApiAnrScalesCommentsController::class => AutowireFactory::class, Controller\ApiAnrRisksController::class => AutowireFactory::class, Controller\ApiAnrRiskOwnersController::class => AutowireFactory::class, Controller\ApiDashboardAnrRisksController::class => AutowireFactory::class, Controller\ApiAnrRisksOpController::class => AutowireFactory::class, - Controller\ApiAnrLibraryController::class => Controller\ApiAnrLibraryControllerFactory::class, - Controller\ApiAnrLibraryCategoryController::class - => Controller\ApiAnrLibraryCategoryControllerFactory::class, - Controller\ApiAnrInstancesController::class => Controller\ApiAnrInstancesControllerFactory::class, - Controller\ApiAnrInstancesRisksController::class => Controller\ApiAnrInstancesRisksControllerFactory::class, + Controller\ApiAnrLibraryController::class => AutowireFactory::class, + Controller\ApiAnrInstancesController::class => AutowireFactory::class, + Controller\ApiAnrInstancesRisksController::class => AutowireFactory::class, Controller\ApiAnrInstancesRisksOpController::class => AutowireFactory::class, - Import\Controller\ApiAnrInstancesImportController::class => AutowireFactory::class, - Controller\ApiAnrInstancesExportController::class - => Controller\ApiAnrInstancesExportControllerFactory::class, - Controller\ApiAnrObjectsCategoriesController::class - => Controller\ApiAnrObjectsCategoriesControllerFactory::class, - Controller\ApiAnrObjectsExportController::class => Controller\ApiAnrObjectsExportControllerFactory::class, - Controller\ApiAnrObjectsImportController::class => AutowireFactory::class, + Controller\ApiSnapshotController::class => AutowireFactory::class, + Controller\ApiAnrObjectsCategoriesController::class => AutowireFactory::class, Controller\ApiAnrDeliverableController::class => AutowireFactory::class, - Controller\ApiAnrExportController::class => AutowireFactory::class, - Controller\ApiAnrInstancesConsequencesController::class - => Controller\ApiAnrInstancesConsequencesControllerFactory::class, - Controller\ApiModelVerifyLanguageController::class - => Controller\ApiModelVerifyLanguageControllerFactory::class, - Controller\ApiDeliveriesModelsController::class => Controller\ApiDeliveriesModelsControllerFactory::class, - StatsController::class => AutowireFactory::class, - StatsAnrsSettingsController::class => AutowireFactory::class, - StatsGeneralSettingsController::class => AutowireFactory::class, + Controller\ApiAnrInstancesConsequencesController::class => AutowireFactory::class, + Controller\ApiModelVerifyLanguageController::class => AutowireFactory::class, Controller\ApiOperationalRisksScalesController::class => AutowireFactory::class, Controller\ApiOperationalRisksScalesCommentsController::class => AutowireFactory::class, - Controller\ApiAnrMetadatasOnInstancesController::class => AutowireFactory::class, + Controller\ApiAnrInstancesMetadataFieldsController::class => AutowireFactory::class, Controller\ApiInstanceMetadataController::class => AutowireFactory::class, Controller\ApiSoaScaleCommentController::class => AutowireFactory::class, + Controller\ApiSystemMessagesController::class => AutowireFactory::class, + Export\Controller\ApiAnrExportController::class => AutowireFactory::class, + Export\Controller\ApiAnrInstancesExportController::class => AutowireFactory::class, + Export\Controller\ApiAnrObjectsExportController::class => AutowireFactory::class, + Import\Controller\ApiAnrInstancesImportController::class => AutowireFactory::class, + Import\Controller\ApiAnrObjectsImportController::class => AutowireFactory::class, + Stats\Controller\StatsController::class => AutowireFactory::class, + Stats\Controller\StatsAnrsSettingsController::class => AutowireFactory::class, + Stats\Controller\StatsGeneralSettingsController::class => AutowireFactory::class, ], ], @@ -1227,75 +1461,64 @@ Entity\UserAnr::class => Entity\UserAnr::class, ], 'factories' => [ + AnrValidationMiddleware::class => AutowireFactory::class, + DbCli::class => Service\Model\DbCliFactory::class, - Table\AmvTable::class => AutowireFactory::class, - Table\AnrObjectCategoryTable::class => AutowireFactory::class, - Table\AnrTable::class => AutowireFactory::class, - Table\AssetTable::class => AutowireFactory::class, - Table\ClientTable::class => AutowireFactory::class, - Table\InstanceTable::class => AutowireFactory::class, - Table\DeliveryTable::class => AutowireFactory::class, - Table\InstanceConsequenceTable::class => AutowireFactory::class, - Table\InstanceRiskTable::class => AutowireFactory::class, - Table\InstanceRiskOpTable::class => AutowireFactory::class, - Table\InterviewTable::class => AutowireFactory::class, - Table\MeasureTable::class => AutowireFactory::class, - Table\MeasureMeasureTable::class => AutowireFactory::class, - Table\MonarcObjectTable::class => AutowireFactory::class, - Table\ObjectCategoryTable::class => AutowireFactory::class, - Table\ObjectObjectTable::class => AutowireFactory::class, - Table\PasswordTokenTable::class => AutowireFactory::class, - Table\RolfRiskTable::class => AutowireFactory::class, - Table\RolfTagTable::class => AutowireFactory::class, - Table\RecordActorTable::class => AutowireFactory::class, - Table\RecordDataCategoryTable::class => AutowireFactory::class, - Table\RecordInternationalTransferTable::class => AutowireFactory::class, - Table\RecordPersonalDataTable::class => AutowireFactory::class, - Table\RecordProcessorTable::class => AutowireFactory::class, - Table\RecordRecipientTable::class => AutowireFactory::class, - Table\RecordTable::class => AutowireFactory::class, - Table\ReferentialTable::class => AutowireFactory::class, - Table\RecommandationTable::class => AutowireFactory::class, - Table\RecommendationHistoricTable::class => AutowireFactory::class, - Table\RecommandationRiskTable::class => AutowireFactory::class, - Table\RecommandationSetTable::class => AutowireFactory::class, - Table\ScaleTable::class => AutowireFactory::class, - Table\ScaleCommentTable::class => AutowireFactory::class, - Table\ScaleImpactTypeTable::class => AutowireFactory::class, - Table\SnapshotTable::class => AutowireFactory::class, - Table\SoaTable::class => AutowireFactory::class, - Table\SoaCategoryTable::class => AutowireFactory::class, - Table\ThemeTable::class => AutowireFactory::class, - Table\ThreatTable::class => AutowireFactory::class, - Table\UserTable::class => AutowireFactory::class, - Table\UserAnrTable::class => AutowireFactory::class, - Table\VulnerabilityTable::class => AutowireFactory::class, - Table\QuestionTable::class => AutowireFactory::class, - Table\QuestionChoiceTable::class => AutowireFactory::class, + DeprecatedTable\InterviewTable::class => AutowireFactory::class, + DeprecatedTable\RecordActorTable::class => AutowireFactory::class, + DeprecatedTable\RecordDataCategoryTable::class => AutowireFactory::class, + DeprecatedTable\RecordInternationalTransferTable::class => AutowireFactory::class, + DeprecatedTable\RecordPersonalDataTable::class => AutowireFactory::class, + DeprecatedTable\RecordProcessorTable::class => AutowireFactory::class, + DeprecatedTable\RecordRecipientTable::class => AutowireFactory::class, + DeprecatedTable\RecordTable::class => AutowireFactory::class, + DeprecatedTable\QuestionTable::class => AutowireFactory::class, + DeprecatedTable\QuestionChoiceTable::class => AutowireFactory::class, + Table\AnrTable::class => ClientEntityManagerFactory::class, + Table\AnrInstanceMetadataFieldTable::class => ClientEntityManagerFactory::class, + Table\AmvTable::class => ClientEntityManagerFactory::class, + Table\AssetTable::class => ClientEntityManagerFactory::class, + Table\DeliveryTable::class => ClientEntityManagerFactory::class, + Table\InstanceTable::class => ClientEntityManagerFactory::class, + Table\InstanceRiskTable::class => ClientEntityManagerFactory::class, + Table\InstanceRiskOpTable::class => ClientEntityManagerFactory::class, + Table\InstanceMetadataTable::class => ClientEntityManagerFactory::class, + Table\InstanceRiskOwnerTable::class => ClientEntityManagerFactory::class, + Table\InstanceConsequenceTable::class => ClientEntityManagerFactory::class, + Table\ScaleTable::class => ClientEntityManagerFactory::class, + Table\ScaleCommentTable::class => ClientEntityManagerFactory::class, + Table\ScaleImpactTypeTable::class => ClientEntityManagerFactory::class, + Table\ClientTable::class => ClientEntityManagerFactory::class, + Table\MonarcObjectTable::class => ClientEntityManagerFactory::class, + Table\MeasureTable::class => ClientEntityManagerFactory::class, + Table\ObjectCategoryTable::class => ClientEntityManagerFactory::class, + Table\ObjectObjectTable::class => ClientEntityManagerFactory::class, Table\OperationalRiskScaleTable::class => ClientEntityManagerFactory::class, Table\OperationalRiskScaleTypeTable::class => ClientEntityManagerFactory::class, Table\OperationalRiskScaleCommentTable::class => ClientEntityManagerFactory::class, Table\OperationalInstanceRiskScaleTable::class => ClientEntityManagerFactory::class, - Table\TranslationTable::class => ClientEntityManagerFactory::class, - Table\InstanceRiskOwnerTable::class => ClientEntityManagerFactory::class, - Table\AnrMetadatasOnInstancesTable::class => ClientEntityManagerFactory::class, - Table\InstanceMetadataTable::class => ClientEntityManagerFactory::class, + Table\RecommendationTable::class => ClientEntityManagerFactory::class, + Table\RecommendationHistoryTable::class => ClientEntityManagerFactory::class, + Table\RecommendationRiskTable::class => ClientEntityManagerFactory::class, + Table\RecommendationSetTable::class => ClientEntityManagerFactory::class, + Table\RolfRiskTable::class => ClientEntityManagerFactory::class, + Table\RolfTagTable::class => ClientEntityManagerFactory::class, + Table\ReferentialTable::class => ClientEntityManagerFactory::class, + Table\SoaCategoryTable::class => ClientEntityManagerFactory::class, + Table\SoaTable::class => ClientEntityManagerFactory::class, + Table\SnapshotTable::class => ClientEntityManagerFactory::class, Table\SoaScaleCommentTable::class => ClientEntityManagerFactory::class, - Table\ClientModelTable::class => ClientEntityManagerFactory::class, - CronTaskTable::class => ClientEntityManagerFactory::class, + Table\SystemMessageTable::class => ClientEntityManagerFactory::class, + Table\ThemeTable::class => ClientEntityManagerFactory::class, + Table\ThreatTable::class => ClientEntityManagerFactory::class, + Table\UserTable::class => ClientEntityManagerFactory::class, + Table\UserAnrTable::class => ClientEntityManagerFactory::class, + Table\UserTokenTable::class => ClientEntityManagerFactory::class, + Table\VulnerabilityTable::class => ClientEntityManagerFactory::class, + CronTask\Table\CronTaskTable::class => ClientEntityManagerFactory::class, - //entities // TODO: the goal is to remove all of the mapping and create new entity in the code. - Entity\Amv::class => ModelFactory\AmvServiceModelEntity::class, - Entity\Anr::class => ModelFactory\AnrServiceModelEntity::class, - Entity\AnrObjectCategory::class => ModelFactory\AnrObjectCategoryServiceModelEntity::class, - Entity\Asset::class => ModelFactory\AssetServiceModelEntity::class, - Entity\Delivery::class => ModelFactory\DeliveryServiceModelEntity::class, - Entity\Instance::class => ModelFactory\InstanceServiceModelEntity::class, - Entity\InstanceConsequence::class => ModelFactory\InstanceConsequenceServiceModelEntity::class, - Entity\InstanceRisk::class => ModelFactory\InstanceRiskServiceModelEntity::class, - Entity\InstanceRiskOp::class => ModelFactory\InstanceRiskOpServiceModelEntity::class, Entity\Interview::class => ModelFactory\InterviewServiceModelEntity::class, Entity\RecordActor::class => ModelFactory\RecordActorServiceModelEntity::class, Entity\RecordDataCategory::class => ModelFactory\RecordDataCategoryServiceModelEntity::class, @@ -1305,44 +1528,11 @@ Entity\RecordProcessor::class => ModelFactory\RecordProcessorServiceModelEntity::class, Entity\RecordRecipient::class => ModelFactory\RecordRecipientServiceModelEntity::class, Entity\Record::class => ModelFactory\RecordServiceModelEntity::class, - Entity\Referential::class => ModelFactory\ReferentialServiceModelEntity::class, - Entity\Measure::class => ModelFactory\MeasureServiceModelEntity::class, - Entity\MeasureMeasure::class => ModelFactory\MeasureMeasureServiceModelEntity::class, - Entity\MonarcObject::class => ModelFactory\MonarcObjectServiceModelEntity::class, - Entity\ObjectCategory::class => ModelFactory\ObjectCategoryServiceModelEntity::class, - Entity\ObjectObject::class => ModelFactory\ObjectObjectServiceModelEntity::class, - Entity\PasswordToken::class => ModelFactory\PasswordTokenServiceModelEntity::class, - Entity\RolfRisk::class => ModelFactory\RolfRiskServiceModelEntity::class, - Entity\RolfTag::class => ModelFactory\RolfTagServiceModelEntity::class, - Entity\Recommandation::class => ModelFactory\RecommandationServiceModelEntity::class, - Entity\RecommandationHistoric::class => ModelFactory\RecommandationHistoricServiceModelEntity::class, - Entity\RecommandationRisk::class => ModelFactory\RecommandationRiskServiceModelEntity::class, - Entity\RecommandationSet::class => ModelFactory\RecommandationSetServiceModelEntity::class, - Entity\Scale::class => ModelFactory\ScaleServiceModelEntity::class, - Entity\ScaleComment::class => ModelFactory\ScaleCommentServiceModelEntity::class, - Entity\ScaleImpactType::class => ModelFactory\ScaleImpactTypeServiceModelEntity::class, - Entity\Snapshot::class => ModelFactory\SnapshotServiceModelEntity::class, - Entity\Soa::class => ModelFactory\SoaServiceModelEntity::class, - Entity\SoaCategory::class => ModelFactory\SoaCategoryServiceModelEntity::class, - Entity\Theme::class => ModelFactory\ThemeServiceModelEntity::class, - Entity\Threat::class => ModelFactory\ThreatServiceModelEntity::class, - Entity\Vulnerability::class => ModelFactory\VulnerabilityServiceModelEntity::class, Entity\Question::class => ModelFactory\QuestionServiceModelEntity::class, Entity\QuestionChoice::class => ModelFactory\QuestionChoiceServiceModelEntity::class, // TODO: replace to autowiring. - Service\AnrService::class => Service\AnrServiceFactory::class, - Service\AnrCoreService::class => Service\AnrCoreServiceFactory::class, - Service\SnapshotService::class => Service\SnapshotServiceFactory::class, - Service\UserService::class => ReflectionBasedAbstractFactory::class, - Service\UserAnrService::class => Service\UserAnrServiceFactory::class, - Service\UserRoleService::class => AutowireFactory::class, - Service\AnrAssetService::class => Service\AnrAssetServiceFactory::class, - Service\AnrAssetCommonService::class => Service\AnrAssetCommonServiceFactory::class, - Service\AnrAmvService::class => Service\AnrAmvServiceFactory::class, Service\AnrInterviewService::class => Service\AnrInterviewServiceFactory::class, - Service\AnrMeasureService::class => Service\AnrMeasureServiceFactory::class, - Service\AnrMeasureMeasureService::class => Service\AnrMeasureMeasureServiceFactory::class, Service\AnrRecordActorService::class => Service\AnrRecordActorServiceFactory::class, Service\AnrRecordDataCategoryService::class => Service\AnrRecordDataCategoryServiceFactory::class, Service\AnrRecordInternationalTransferService::class @@ -1351,115 +1541,231 @@ Service\AnrRecordProcessorService::class => Service\AnrRecordProcessorServiceFactory::class, Service\AnrRecordRecipientService::class => Service\AnrRecordRecipientServiceFactory::class, Service\AnrRecordService::class => Service\AnrRecordServiceFactory::class, - Service\AnrReferentialService::class => Service\AnrReferentialServiceFactory::class, - Service\SoaService::class => Service\SoaServiceFactory::class, - Service\SoaCategoryService::class => Service\SoaCategoryServiceFactory::class, Service\AnrQuestionService::class => Service\AnrQuestionServiceFactory::class, Service\AnrQuestionChoiceService::class => Service\AnrQuestionChoiceServiceFactory::class, - Service\AnrThreatService::class => Service\AnrThreatServiceFactory::class, - Service\AnrThemeService::class => Service\AnrThemeServiceFactory::class, - Service\AnrVulnerabilityService::class => Service\AnrVulnerabilityServiceFactory::class, - Service\AnrRolfTagService::class => Service\AnrRolfTagServiceFactory::class, - Service\AnrRolfRiskService::class => Service\AnrRolfRiskServiceFactory::class, - Service\AmvService::class => Service\AmvServiceFactory::class, + Service\AnrMeasureService::class => AutowireFactory::class, + Service\AnrMeasureLinkService::class => AutowireFactory::class, + Service\AnrReferentialService::class => AutowireFactory::class, + Service\SoaCategoryService::class => AutowireFactory::class, + Service\AnrRolfTagService::class => AutowireFactory::class, + Service\AnrRolfRiskService::class => AutowireFactory::class, + Service\AnrRecommendationService::class => AutowireFactory::class, + Service\AnrRecommendationHistoryService::class => AutowireFactory::class, + Service\AnrRecommendationRiskService::class => AutowireFactory::class, + Service\AnrRecommendationSetService::class => AutowireFactory::class, + Service\AnrCartoRiskService::class => AutowireFactory::class, + Service\DeliverableGenerationService::class => AutowireFactory::class, + Service\SnapshotService::class => AutowireFactory::class, + Service\AnrService::class => AutowireFactory::class, + Service\UserService::class => ReflectionBasedAbstractFactory::class, + Service\UserRoleService::class => AutowireFactory::class, + Service\AnrAssetService::class => AutowireFactory::class, + Service\AnrAmvService::class => AutowireFactory::class, + Service\AnrThreatService::class => AutowireFactory::class, + Service\AnrThemeService::class => AutowireFactory::class, + Service\AnrVulnerabilityService::class => AutowireFactory::class, Service\ClientService::class => AutowireFactory::class, - Service\ObjectObjectService::class => Service\ObjectObjectServiceFactory::class, - Service\ModelService::class => Service\ModelServiceFactory::class, - Service\AnrLibraryService::class => Service\AnrLibraryServiceFactory::class, - Service\AnrRecommandationService::class => Service\AnrRecommandationServiceFactory::class, - Service\AnrRecommandationHistoricService::class => Service\AnrRecommandationHistoricServiceFactory::class, - Service\AnrRecommandationRiskService::class => Service\AnrRecommandationRiskServiceFactory::class, - Service\AnrRecommandationSetService::class => Service\AnrRecommandationSetServiceFactory::class, - Service\AnrScaleService::class => Service\AnrScaleServiceFactory::class, - Service\AnrScaleTypeService::class => Service\AnrScaleTypeServiceFactory::class, - Service\AnrScaleCommentService::class => Service\AnrScaleCommentServiceFactory::class, - Service\AnrCheckStartedService::class => AutowireFactory::class, - Service\AnrCartoRiskService::class => Service\AnrCartoRiskServiceFactory::class, - Service\AnrObjectService::class => Service\AnrObjectServiceFactory::class, - Service\AnrInstanceConsequenceService::class => Service\AnrInstanceConsequenceServiceFactory::class, + Service\AnrScaleService::class => AutowireFactory::class, + Service\AnrScaleImpactTypeService::class => AutowireFactory::class, + Service\AnrScaleCommentService::class => AutowireFactory::class, + Service\AnrObjectService::class => AutowireFactory::class, + Service\AnrObjectObjectService::class => AutowireFactory::class, + Service\AnrInstanceConsequenceService::class => AutowireFactory::class, Service\AnrInstanceRiskOpService::class => AutowireFactory::class, - Service\AnrInstanceRiskService::class => Service\AnrInstanceRiskServiceFactory::class, - Service\AnrInstanceService::class => Service\AnrInstanceServiceFactory::class, - Service\AnrObjectCategoryService::class => Service\AnrObjectCategoryServiceFactory::class, - Service\AssetExportService::class => Service\AssetExportServiceFactory::class, - Service\DeliverableGenerationService::class => Service\DeliverableGenerationServiceFactory::class, - Service\ObjectExportService::class => AutowireFactory::class, - Import\Service\ObjectImportService::class => AutowireFactory::class, - Import\Service\AssetImportService::class => AutowireFactory::class, - Import\Service\InstanceImportService::class => AutowireFactory::class, - StatsAnrService::class => ReflectionBasedAbstractFactory::class, - StatsSettingsService::class => AutowireFactory::class, + Service\AnrInstanceRiskService::class => AutowireFactory::class, + Service\AnrInstanceService::class => AutowireFactory::class, Service\OperationalRiskScaleService::class => AutowireFactory::class, Service\InstanceRiskOwnerService::class => AutowireFactory::class, Service\OperationalRiskScaleCommentService::class => AutowireFactory::class, - OperationalRiskScalesExportService::class => static function (ContainerInterface $container, $serviceName) { - return new OperationalRiskScalesExportService( + Service\AnrInstanceMetadataFieldService::class => AutowireFactory::class, + Service\InstanceMetadataService::class => AutowireFactory::class, + Service\SoaService::class => AutowireFactory::class, + Service\SoaScaleCommentService::class => AutowireFactory::class, + Service\SystemMessageService::class => AutowireFactory::class, + Stats\Service\StatsAnrService::class => ReflectionBasedAbstractFactory::class, + Stats\Service\StatsSettingsService::class => AutowireFactory::class, + CronTask\Service\CronTaskService::class => AutowireFactory::class, + /* Export services. */ + Export\Service\AnrExportService::class => AutowireFactory::class, + Export\Service\ObjectExportService::class => AutowireFactory::class, + Export\Service\InstanceExportService::class => AutowireFactory::class, + /* Import services. */ + Import\Service\ObjectImportService::class => AutowireFactory::class, + Import\Service\InstanceImportService::class => AutowireFactory::class, + + // Helpers + Import\Helper\ImportCacheHelper::class => AutowireFactory::class, + ScalesCacheHelper::class => static function (ContainerInterface $container) { + return new ScalesCacheHelper( + $container->get(Table\ScaleTable::class), + $container->get(Table\ScaleImpactTypeTable::class), $container->get(Table\OperationalRiskScaleTable::class), - $container->get(Table\TranslationTable::class), - $container->get(ConfigService::class), ); }, - AnrMetadatasOnInstancesExportService::class => static function ( - ContainerInterface $container, - $serviceName - ) { - return new AnrMetadatasOnInstancesExportService( - $container->get(Table\AnrMetadatasOnInstancesTable::class), - $container->get(Table\TranslationTable::class), - $container->get(ConfigService::class), + + /* Authentication */ + StorageAuthentication::class => static function (ContainerInterface $container) { + return new StorageAuthentication( + $container->get(Table\UserTokenTable::class), + $container->get('config') ); }, - Service\AnrMetadatasOnInstancesService::class => AutowireFactory::class, - Service\InstanceMetadataService::class => AutowireFactory::class, - Service\SoaScaleCommentService::class => AutowireFactory::class, - SoaScaleCommentExportService::class => static function ( - ContainerInterface $container, - $serviceName - ) { - return new SoaScaleCommentExportService( - $container->get(Table\SoaScaleCommentTable::class), - $container->get(Table\TranslationTable::class), - $container->get(ConfigService::class), + AdapterAuthentication::class => static function (ContainerInterface $container) { + return new AdapterAuthentication( + $container->get(Table\UserTable::class), + $container->get(ConfigService::class) + ); + }, + ConnectedUserService::class => static function (ContainerInterface $container) { + return new ConnectedUserService( + $container->get(Request::class), + $container->get(Table\UserTokenTable::class) ); }, - CronTaskService::class => AutowireFactory::class, - - // Helpers - Import\Helper\ImportCacheHelper::class => AutowireFactory::class, // Providers - StatsApiProvider::class => ReflectionBasedAbstractFactory::class, + Stats\Provider\StatsApiProvider::class => ReflectionBasedAbstractFactory::class, // Validators - CreateUserInputValidator::class => ReflectionBasedAbstractFactory::class, - GetStatsQueryParamsValidator::class => GetStatsQueryParamsValidatorFactory::class, - GetProcessedStatsQueryParamsValidator::class => GetProcessedStatsQueryParamsValidatorFactory::class, + InputValidator\User\PostUserDataInputValidator::class => ReflectionBasedAbstractFactory::class, + Stats\Validator\GetStatsQueryParamsValidator::class => ReflectionBasedAbstractFactory::class, + Stats\Validator\GetProcessedStatsQueryParamsValidator::class => ReflectionBasedAbstractFactory::class, + InputValidator\Anr\CreateAnrDataInputValidator::class => ReflectionBasedAbstractFactory::class, + InputValidator\Object\PostObjectDataInputValidator::class => ReflectionBasedAbstractFactory::class, + InputValidator\Object\DuplicateObjectDataInputValidator::class => ReflectionBasedAbstractFactory::class, + InputValidator\Recommendation\PostRecommendationDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new InputValidator\Recommendation\PostRecommendationDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\RecommendationTable::class) + ); + }, + InputValidator\Recommendation\PatchRecommendationDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new InputValidator\Recommendation\PatchRecommendationDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\RecommendationTable::class) + ); + }, + InputValidator\RecommendationSet\PostRecommendationSetDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\RecommendationRisk\ValidateRecommendationRiskDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\RecommendationRisk\PostRecommendationRiskDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\RecommendationRisk\PatchRecommendationRiskDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\InstanceRisk\PostSpecificInstanceRiskDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\InstanceRisk\UpdateInstanceRiskDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\InstanceRiskOp\PostSpecificInstanceRiskOpDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\InstanceRiskOp\UpdateInstanceRiskOpDataInputValidator::class => + ReflectionBasedAbstractFactory::class, + InputValidator\Threat\PostThreatDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new InputValidator\Threat\PostThreatDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\ThreatTable::class) + ); + }, + CoreInputValidator\Asset\PostAssetDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new CoreInputValidator\Asset\PostAssetDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\AssetTable::class) + ); + }, + CoreInputValidator\Vulnerability\PostVulnerabilityDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new CoreInputValidator\Vulnerability\PostVulnerabilityDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\VulnerabilityTable::class) + ); + }, + CoreInputValidator\RolfRisk\PostRolfRiskDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new CoreInputValidator\RolfRisk\PostRolfRiskDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\RolfRiskTable::class) + ); + }, + CoreInputValidator\RolfTag\PostRolfTagDataInputValidator::class => static function ( + Containerinterface $container + ) { + return new CoreInputValidator\RolfTag\PostRolfTagDataInputValidator( + $container->get('config'), + $container->get(CoreInputValidator\InputValidationTranslator::class), + $container->get(Table\RolfTagTable::class) + ); + }, // Commands - Import\Command\ImportAnalysesCommand::class => static function ( - ContainerInterface $container, - $serviceName - ) { + Import\Command\ImportAnalysesCommand::class => static function (ContainerInterface $container) { /** @var ConnectedUserService $connectedUserService */ $connectedUserService = $container->get(ConnectedUserService::class); - $connectedUserService->setConnectedUser(new User([ + $connectedUserService->setConnectedUser(new Entity\User([ 'firstname' => 'System', 'lastname' => 'System', 'email' => 'System', 'language' => 1, 'mospApiKey' => '', 'creator' => 'System', - 'role' => [UserRoleSuperClass::USER_ROLE_SYSTEM], + 'role' => [Entity\UserRole::USER_ROLE_SYSTEM], ])); return new Import\Command\ImportAnalysesCommand( - $container->get(CronTaskService::class), + $container->get(CronTask\Service\CronTaskService::class), $container->get(Import\Service\InstanceImportService::class), $container->get(Table\AnrTable::class), $container->get(Service\SnapshotService::class) ); }, ], + 'lazy_services' => [ + 'class_map' => [ + Table\UserTokenTable::class => Table\UserTokenTable::class, + Service\AnrInstanceService::class => Service\AnrInstanceService::class, + Import\Processor\ObjectCategoryImportProcessor::class => + Import\Processor\ObjectCategoryImportProcessor::class, + Import\Processor\InformationRiskImportProcessor::class => + Import\Processor\InformationRiskImportProcessor::class, + Import\Processor\OperationalRiskImportProcessor::class => + Import\Processor\OperationalRiskImportProcessor::class, + ], + 'proxies_target_dir' => $dataPath . '/LazyServices/Proxy', + 'write_proxy_files' => $env === 'production', + ], + 'delegators' => [ + Table\UserTokenTable::class => [ + LazyServiceFactory::class, + ], + Service\AnrInstanceService::class => [ + LazyServiceFactory::class, + ], + Import\Processor\ObjectCategoryImportProcessor::class => [ + LazyServiceFactory::class, + ], + Import\Processor\InformationRiskImportProcessor::class => [ + LazyServiceFactory::class, + ], + Import\Processor\OperationalRiskImportProcessor::class => [ + LazyServiceFactory::class, + ], + ], ], 'doctrine' => [ @@ -1476,7 +1782,7 @@ 'orm_cli' => [ 'class' => MappingDriverChain::class, 'drivers' => [ - 'Monarc\FrontOffice\Model\Entity' => 'Monarc_cli_driver', + 'Monarc\FrontOffice\Entity' => 'Monarc_cli_driver', ], ], ], @@ -1512,6 +1818,7 @@ 'monarc_api_stats_global/processed', 'monarc_api_stats_global/general_settings', 'monarc_api_stats_global/validate-stats-availability', + 'monarc_api_system_messages', ], // User : RWD access per analysis Entity\UserRole::USER_FO => [ @@ -1519,7 +1826,7 @@ 'monarc_api_models', 'monarc_api_referentials', 'monarc_api_admin_users_roles', - 'monarc_api_global_client_anr/anr_metadatas_on_instances', + 'monarc_api_global_client_anr/anr_instance_metadata_field', 'monarc_api_global_client_anr/instance_metadata', 'monarc_api_global_client_anr/instance', 'monarc_api_global_client_anr/instance_risk', @@ -1537,7 +1844,6 @@ 'monarc_api_global_client_anr/export', 'monarc_api_guides', 'monarc_api_guides_items', - 'monarc_api_anr_objects_parents', 'monarc_api_global_client_anr/questions', 'monarc_api_global_client_anr/questions_choices', 'monarc_api_global_client_anr/soa', @@ -1578,12 +1884,12 @@ 'monarc_api_client_anr_scales', 'monarc_api_client_anr_scales_types', 'monarc_api_client_anr_scales_comments', - 'monarc_api_anr_recommandations', - 'monarc_api_anr_recommandations_historics', - 'monarc_api_anr_recommandations_risks', - 'monarc_api_anr_recommandations_risks_validate', - 'monarc_api_anr_recommandations_measures', - 'monarc_api_anr_recommandations_sets', + 'monarc_api_anr_recommendations', + 'monarc_api_anr_recommendations_history', + 'monarc_api_anr_recommendations_risks', + 'monarc_api_anr_recommendations_risks_validate', + 'monarc_api_anr_recommendations_measures', + 'monarc_api_anr_recommendations_sets', 'monarc_api_anr_treatment_plan', 'monarc_api_anr_client_objects_categories', 'monarc_api_user_password', @@ -1597,12 +1903,12 @@ 'monarc_api_global_client_anr/scales_comments', 'monarc_api_global_client_anr/operational_scales', 'monarc_api_global_client_anr/operational_scales_comment', - 'monarc_api_global_client_anr/recommandations', - 'monarc_api_global_client_anr/recommandations_historics', - 'monarc_api_global_client_anr/recommandations_risks', - 'monarc_api_global_client_anr/recommandations_risks_validate', - 'monarc_api_global_client_anr/recommandations_measures', - 'monarc_api_global_client_anr/recommandations_sets', + 'monarc_api_global_client_anr/recommendations', + 'monarc_api_global_client_anr/recommendations_history', + 'monarc_api_global_client_anr/recommendations_risks', + 'monarc_api_global_client_anr/recommendations_risks_validate', + 'monarc_api_global_client_anr/recommendations_measures', + 'monarc_api_global_client_anr/recommendations_sets', 'monarc_api_global_client_anr/treatment_plan', 'monarc_api_global_client_anr/objects_categories', 'monarc_api_global_client_anr/records', @@ -1620,6 +1926,7 @@ 'monarc_api_stats_global/processed', 'monarc_api_stats_global/general_settings', 'monarc_api_stats_global/validate-stats-availability', + 'monarc_api_system_messages', ], Entity\UserRole::USER_ROLE_CEO => [ 'monarc_api_admin_users_roles', @@ -1634,6 +1941,7 @@ 'monarc_api_stats_global/anrs_settings', 'monarc_api_stats_global/general_settings', 'monarc_api_stats_global/validate-stats-availability', + 'monarc_api_system_messages', ], ], 'activeLanguages' => ['fr'], diff --git a/migrations/db/20210521090000_changeable_operational_impact.php b/migrations/db/20210521090000_changeable_operational_impact.php index b52bb444..bdf5cba3 100644 --- a/migrations/db/20210521090000_changeable_operational_impact.php +++ b/migrations/db/20210521090000_changeable_operational_impact.php @@ -1,8 +1,8 @@ execute('update users set recovery_codes = "' . serialize([]) . '" where recovery_codes IS NULL'); + $this->execute('ALTER TABLE `amvs` MODIFY updated_at datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP;'); + + /* Fix the amvs positions. */ + $amvsQuery = $this->query( + 'SELECT uuid, anr_id, asset_id, position FROM `amvs` ORDER BY anr_id, asset_id, position' + ); + $previousAssetUuid = null; + $previousAnrId = null; + $expectedAmvPosition = 1; + foreach ($amvsQuery->fetchAll() as $amvData) { + if ($previousAssetUuid === null) { + $previousAssetUuid = $amvData['asset_id']; + $previousAnrId = $amvData['anr_id']; + } + if ($amvData['asset_id'] !== $previousAssetUuid + || $previousAnrId !== $amvData['anr_id'] + ) { + $expectedAmvPosition = 1; + } + + if ($expectedAmvPosition !== $amvData['position']) { + $this->execute( + sprintf( + 'UPDATE amvs SET position = %d WHERE uuid = "%s"', + $expectedAmvPosition, + $amvData['uuid'] + ) + ); + } + + $expectedAmvPosition++; + $previousAssetUuid = $amvData['asset_id']; + $previousAnrId = $amvData['anr_id']; + } + + /* Fix the objects compositions positions. */ + $objectsQuery = $this->query( + 'SELECT id, anr_id, father_id, position FROM objects_objects ORDER BY anr_id, father_id, position' + ); + $previousParentObjectId = null; + $previousAnrId = null; + $expectedCompositionLinkPosition = 1; + foreach ($objectsQuery->fetchAll() as $compositionObjectsData) { + if ($previousParentObjectId === null) { + $previousParentObjectId = $compositionObjectsData['father_id']; + $previousAnrId = $compositionObjectsData['anr_id']; + } + if ($compositionObjectsData['father_id'] !== $previousParentObjectId + || $previousAnrId !== $compositionObjectsData['anr_id'] + ) { + $expectedCompositionLinkPosition = 1; + } + + if ($expectedCompositionLinkPosition !== $compositionObjectsData['position']) { + $this->execute(sprintf( + 'UPDATE objects_objects SET position = %d WHERE id = %d', + $expectedCompositionLinkPosition, + $compositionObjectsData['id'] + )); + } + + $expectedCompositionLinkPosition++; + $previousParentObjectId = $compositionObjectsData['father_id']; + $previousAnrId = $compositionObjectsData['anr_id']; + } + /* Add a unique key for the object composition. */ + $this->table('objects_objects')->addIndex(['father_id', 'child_id', 'anr_id'], ['unique' => true])->update(); + + /* Fix the objects categories positions. */ + $objectsCategoriesQuery = $this->query( + 'SELECT id, anr_id, parent_id, position FROM objects_categories ORDER BY anr_id, parent_id, position' + ); + $previousParentCategoryId = -1; + $previousAnrId = null; + $expectedCategoryPosition = 1; + foreach ($objectsCategoriesQuery->fetchAll() as $objectCategoryData) { + if ($previousParentCategoryId === -1) { + $previousParentCategoryId = $objectCategoryData['parent_id']; + $previousAnrId = $objectCategoryData['anr_id']; + } + if ($objectCategoryData['parent_id'] !== $previousParentCategoryId + || $previousAnrId !== $objectCategoryData['anr_id'] + ) { + $expectedCategoryPosition = 1; + } + + if ($expectedCategoryPosition !== $objectCategoryData['position']) { + $this->execute( + sprintf( + 'UPDATE objects_categories SET position = %d WHERE id = %d', + $expectedCategoryPosition, + $objectCategoryData['id'] + ) + ); + } + + $expectedCategoryPosition++; + $previousParentCategoryId = $objectCategoryData['parent_id']; + $previousAnrId = $objectCategoryData['anr_id']; + } + + /* Fix instances positions to have them in a correct sequence (1, 2, 3, ...). */ + $instancesQuery = $this->query( + 'SELECT id, anr_id, parent_id, position FROM instances ORDER BY anr_id, parent_id, position' + ); + $previousParentInstanceId = null; + $expectedInstancePosition = 1; + foreach ($instancesQuery->fetchAll() as $instanceData) { + if ($previousParentInstanceId === null) { + $previousParentInstanceId = (int)$instanceData['parent_id']; + } + if ((int)$instanceData['parent_id'] !== $previousParentInstanceId) { + $expectedInstancePosition = 1; + } + + if ($expectedInstancePosition !== $instanceData['position']) { + $this->execute(sprintf( + 'UPDATE instances SET position = %d WHERE id = %d', + $expectedInstancePosition, + $instanceData['id'] + )); + } + + $expectedInstancePosition++; + $previousParentInstanceId = $instanceData['parent_id']; + } + + /* Clean up unused columns. */ + $this->table('clients')->removeColumn('model_id')->update(); + $this->table('instances') + ->removeColumn('disponibility') + ->removeColumn('asset_type') + ->removeColumn('exportable') + ->update(); + $this->table('objects') + ->removeColumn('disponibility') + ->removeColumn('token_import') + ->removeColumn('original_name') + ->removeColumn('position') + ->update(); + $this->table('instances_consequences')->removeColumn('object_id')->removeColumn('locally_touched')->update(); + + /* Fix possibly missing soacategory. */ + $measuresQuery = $this->query( + 'SELECT uuid, referential_uuid, anr_id FROM measures WHERE soacategory_id IS NULL;' + ); + $soaCategoryIds = []; + $soaCategoryTable = $this->table('soacategory'); + foreach ($measuresQuery->fetchAll() as $measureData) { + $anrId = (int)$measureData['anr_id']; + if (!isset($soaCategoryIds[$anrId])) { + $soaCategoryTable->insert([ + 'label1' => 'catégorie manquante', + 'label2' => 'missing category', + 'label3' => 'fehlende Kategorie', + 'label4' => 'ontbrekende categorie', + 'anr_id' => $anrId, + 'referential_uuid' => $measureData['referential_uuid'], + ])->saveData(); + $soaCategoryIds[$anrId] = (int)$this->getAdapter()->getConnection()->lastInsertId(); + } + + $this->execute('UPDATE measures SET soacategory_id = ' . $soaCategoryIds[$anrId] + . ' WHERE uuid = "' . $measureData['uuid'] . '" and anr_id = ' . $anrId); + } + + /* Replace UUID identifier in measures table to ID. */ + $this->table('measures') + ->addColumn('id', 'integer', ['signed' => false, 'after' => MysqlAdapter::FIRST]) + ->update(); + $this->execute('SET @a = 0; UPDATE measures SET id = @a := @a + 1 ORDER BY anr_id;'); + $this->table('measures')->changePrimaryKey(['id'])->addIndex(['uuid', 'anr_id'], ['unique' => true])->update(); + $this->table('measures')->changeColumn('id', 'integer', ['identity' => true, 'signed' => false])->update(); + + /* Correct MeasuresMeasures table structure. */ + $this->table('measures_measures') + ->addColumn('id', 'integer', ['signed' => false, 'after' => MysqlAdapter::FIRST]) + ->addColumn('master_measure_id', 'integer', ['signed' => false, 'after' => 'id']) + ->addColumn('linked_measure_id', 'integer', ['signed' => false, 'after' => 'master_measure_id']) + ->dropForeignKey(['father_id', 'child_id', 'anr_id']) + ->removeColumn('creator') + ->removeColumn('created_at') + ->removeColumn('updater') + ->removeColumn('updated_at') + ->update(); + $this->execute('SET @a = 0; UPDATE measures_measures SET id = @a := @a + 1 ORDER BY anr_id;'); + $this->table('measures_measures') + ->changePrimaryKey(['id']) + ->update(); + $this->table('measures_measures') + ->changeColumn('id', 'integer', ['identity' => true, 'signed' => false]) + ->update(); + /* Remove unlinked measures links with measures and update the new relation field. */ + $this->execute('UPDATE measures_measures mm INNER JOIN measures m ' + . 'ON mm.father_id = m.`uuid` AND mm.anr_id = m.anr_id SET master_measure_id = m.id;'); + $this->execute('UPDATE measures_measures mm INNER JOIN measures m ' + . 'ON mm.child_id = m.`uuid` AND mm.anr_id = m.anr_id SET linked_measure_id = m.id;'); + $this->execute('DELETE FROM measures_measures WHERE master_measure_id IS NULL OR linked_measure_id IS NULL;'); + $this->table('measures_measures') + ->removeColumn('anr_id') + ->removeColumn('father_id') + ->removeColumn('child_id') + ->addForeignKey('master_measure_id', 'measures', 'id', ['delete' => 'CASCADE', 'update' => 'RESTRICT']) + ->addForeignKey('linked_measure_id', 'measures', 'id', ['delete' => 'CASCADE', 'update' => 'RESTRICT']) + ->addIndex(['master_measure_id', 'linked_measure_id'], ['unique' => true]) + ->update(); + /* Apply measures relation to soa. */ + $this->table('soa') + ->renameColumn('measure_id', 'measure_uuid') + ->dropForeignKey(['measure_uuid', 'anr_id']) + ->update(); + $this->table('soa') + ->addColumn('measure_id', 'integer', ['signed' => false, 'after' => 'id']) + ->update(); + $this->execute('UPDATE soa s INNER JOIN measures m ' + . 'ON s.measure_uuid = m.`uuid` AND s.anr_id = m.anr_id SET s.measure_id = m.id;'); + $this->table('soa') + ->addForeignKey('measure_id', 'measures', 'id', ['delete' => 'CASCADE', 'update' => 'RESTRICT']) + ->removeColumn('measure_uuid') + ->update(); + /* Apply measures relation to measures_amvs. */ + $this->table('measures_amvs') + ->removeColumn('anr_id2') + ->removeColumn('creator') + ->removeColumn('created_at') + ->removeColumn('updater') + ->removeColumn('updated_at') + ->renameColumn('measure_id', 'measure_uuid') + ->dropForeignKey(['measure_uuid', 'anr_id']) + ->update(); + $this->table('measures_amvs') + ->addColumn('measure_id', 'integer', ['signed' => false, 'after' => MysqlAdapter::FIRST]) + ->update(); + $this->execute('UPDATE measures_amvs ma INNER JOIN measures m ' + . 'ON ma.measure_uuid = m.`uuid` AND ma.anr_id = m.anr_id SET ma.measure_id = m.id;'); + $this->table('measures_amvs') + ->changePrimaryKey(['measure_id', 'amv_id', 'anr_id']) + ->addForeignKey('measure_id', 'measures', 'id', ['delete' => 'CASCADE', 'update' => 'RESTRICT']) + ->addForeignKey( + ['amv_id', 'anr_id'], + 'amvs', + ['uuid', 'anr_id'], + ['delete' => 'CASCADE', 'update' => 'RESTRICT'] + ) + ->update(); + $this->table('measures_amvs')->removeColumn('measure_uuid')->update(); + /* Apply measures relation to measures_rolf_risks. */ + $this->table('measures_rolf_risks') + ->removeColumn('creator') + ->removeColumn('created_at') + ->removeColumn('updater') + ->removeColumn('updated_at') + ->renameColumn('measure_id', 'measure_uuid') + ->dropForeignKey(['measure_uuid', 'anr_id']) + ->update(); + $this->table('measures_rolf_risks') + ->addColumn('measure_id', 'integer', ['signed' => false, 'after' => 'id']) + ->update(); + $this->execute('UPDATE measures_rolf_risks mr INNER JOIN measures m ' + . 'ON mr.measure_uuid = m.`uuid` AND mr.anr_id = m.anr_id SET mr.measure_id = m.id;'); + $this->table('measures_rolf_risks') + ->addForeignKey('measure_id', 'measures', 'id', ['delete' => 'CASCADE', 'update' => 'RESTRICT']) + ->removeColumn('measure_uuid') + ->removeColumn('anr_id') + ->update(); + + /* Rename column of owner_id to risk_owner_id. */ + $this->table('instances_risks')->renameColumn('owner_id', 'risk_owner_id')->update(); + $this->table('instances_risks_op') + ->renameColumn('owner_id', 'risk_owner_id') + ->removeColumn('brut_r') + ->removeColumn('brut_o') + ->removeColumn('brut_l') + ->removeColumn('brut_f') + ->removeColumn('brut_p') + ->removeColumn('net_r') + ->removeColumn('net_o') + ->removeColumn('net_l') + ->removeColumn('net_f') + ->removeColumn('net_p') + ->removeColumn('targeted_r') + ->removeColumn('targeted_o') + ->removeColumn('targeted_l') + ->removeColumn('targeted_f') + ->removeColumn('targeted_p') + ->update(); + + /* The tables are not needed. */ + $this->table('anrs_objects')->drop()->update(); + $this->table('anrs_objects_categories')->drop()->update(); + + /* Rename table `anr_metadatas_on_instances` to `anr_instance_metadata_fields`. */ + $this->table('anr_metadatas_on_instances')->rename('anr_instance_metadata_fields')->update(); + /* Rename table `instances_metadatas` to `instances_metadata`. */ + $this->table('instances_metadatas')->rename('instances_metadata')->update(); + + /* + * Migrations for to move the data from translations table and remove it. + * 1. Create the fields to insert the data. + * 2. Copy the data from translations + * 3. Remove the translation keys' columns and the translations table. + */ + $this->table('anr_instance_metadata_fields') + ->changeColumn('anr_id', 'integer', ['signed' => false, 'null' => false]) + ->addColumn('label', 'string', ['null' => false, 'limit' => 255, 'default' => '']) + ->update(); + $this->table('instances_metadata') + ->addColumn('comment', 'text', ['null' => true, 'limit' => MysqlAdapter::TEXT_REGULAR]) + ->update(); + $this->table('operational_risks_scales_types') + ->addColumn('label', 'string', ['null' => false, 'limit' => 255, 'default' => '']) + ->update(); + $this->table('operational_risks_scales_comments') + ->addColumn('comment', 'text', ['null' => true, 'limit' => MysqlAdapter::TEXT_REGULAR]) + ->update(); + $this->table('soa_scale_comments') + ->addColumn('comment', 'text', ['null' => true, 'limit' => MysqlAdapter::TEXT_REGULAR]) + ->update(); + + $this->execute( + 'UPDATE anr_instance_metadata_fields aim + INNER JOIN translations t ON aim.label_translation_key = t.translation_key + AND t.anr_id = aim.anr_id + AND t.type = "anr-metadatas-on-instances" + SET aim.label = t.value;' + ); + $this->execute( + 'UPDATE instances_metadata im + INNER JOIN anr_instance_metadata_fields aimf ON im.metadata_id = aimf.id + INNER JOIN translations t ON im.comment_translation_key = t.translation_key + AND t.anr_id = aimf.anr_id + AND t.type = "instance-metadata" + SET im.comment = t.value;' + ); + $this->execute( + 'UPDATE operational_risks_scales_types orst + INNER JOIN translations t ON orst.label_translation_key = t.translation_key + AND t.anr_id = orst.anr_id + AND t.type = "operational-risk-scale-type" + SET orst.label = t.value;' + ); + $this->execute( + 'UPDATE operational_risks_scales_comments orsc + INNER JOIN translations t ON orsc.comment_translation_key = t.translation_key + AND t.anr_id = orsc.anr_id + AND t.type = "operational-risk-scale-comment" + SET orsc.comment = t.value;' + ); + $this->execute( + 'UPDATE soa_scale_comments ssc + INNER JOIN translations t ON ssc.comment_translation_key = t.translation_key + AND t.anr_id = ssc.anr_id + AND t.type = "soa-scale-comment" + SET ssc.comment = t.value;' + ); + + /* Add label, name, description, comment columns to replace all the language specific fields (1, 2, 3, 4). */ + $this->table('anrs') + ->renameColumn('cache_model_is_scales_updatable', 'cache_model_are_scales_updatable') + ->addColumn('label', 'string', ['null' => false, 'limit' => 255, 'default' => '']) + ->addColumn('description', 'text', ['null' => true, 'limit' => MysqlAdapter::TEXT_REGULAR]) + ->addColumn('language_code', 'string', ['null' => false, 'limit' => 255, 'default' => 'fr']) + /* Make Anr name (label) unique. */ + //->addIndex(['label'], ['unique' => true]) + ->update(); + $anrsQuery = $this->query('SELECT id, language, label1, label2, label3, label4, + description1, description2, description3, description4, created_at FROM anrs' + ); + $languageCodes = [1 => 'fr', 2 => 'en', 3 => 'de', 4 => 'nl']; + $uniqueLabels = []; + foreach ($anrsQuery->fetchAll() as $anrData) { + $labelName = 'label' . $anrData['language']; + if (isset($uniqueLabels[$anrData[$labelName]])) { + $uniqueLabels[$anrData[$labelName]] = $anrData[$labelName] . ' [' + . (!empty($anrData['created_at']) ? $anrData['created_at'] : date('Y-m-d H:i:s')) . ']'; + } else { + $uniqueLabels[$anrData[$labelName]] = $anrData[$labelName]; + } + $descriptionName = 'description' . $anrData['language']; + $languageCode = $languageCodes[$anrData['language']]; + $this->execute('UPDATE anrs SET label = "' . $uniqueLabels[$anrData[$labelName]] . + '", description = "' . $anrData[$descriptionName] . + '", language_code = "' . $languageCode . '" WHERE id = ' . (int)$anrData['id']); + } + + /* Replace in recommandations_sets label1,2,3,4 by a single label field. */ + $this->table('recommandations_sets') + ->addColumn('label', 'string', ['null' => false, 'limit' => 255, 'default' => '']) + ->update(); + $recSetsQuery = $this->query('SELECT rs.uuid, rs.anr_id, a.language, rs.label1, rs.label2, rs.label3, rs.label4 + FROM recommandations_sets rs INNER JOIN anrs a ON a.id = rs.anr_id' + ); + foreach ($recSetsQuery->fetchAll() as $recSetData) { + $labelName = 'label' . $recSetData['language']; + $this->execute('UPDATE recommandations_sets SET label = "' . $recSetData[$labelName] . '"' . + ' WHERE uuid = "' . $recSetData['uuid'] . '" AND anr_id = ' . (int)$recSetData['anr_id']); + } + /* Make anr_id and label unique. */ + $this->table('recommandations_sets')->addIndex(['anr_id', 'label'], ['unique' => true])->update(); + + $this->table('recommandations') + ->removeColumn('token_import') + ->removeColumn('original_code') + ->update(); + + $this->table('deliveries') + ->renameColumn('resp_smile', 'responsible_manager') + ->update(); + + $this->table('scales_impact_types') + ->removeColumn('position') + ->update(); + + $this->table('objects_categories') + ->changeColumn('label1', 'string', ['default' => '', 'limit' => 2048]) + ->changeColumn('label2', 'string', ['default' => '', 'limit' => 2048]) + ->changeColumn('label3', 'string', ['default' => '', 'limit' => 2048]) + ->changeColumn('label4', 'string', ['default' => '', 'limit' => 2048]) + ->update(); + + /* The unique relation is not correct as it should be possible to instantiate the same operational risk. */ + $this->table('operational_instance_risks_scales') + ->removeIndex(['anr_id', 'instance_risk_op_id', 'operational_risk_scale_type_id']) + ->addIndex(['anr_id', 'instance_risk_op_id', 'operational_risk_scale_type_id'], ['unique' => false]) + ->update(); + + /* Note: Temporary change fields types to avoid setting values from the code. Later will be dropped. */ + $this->table('operational_risks_scales_types') + ->changeColumn('label_translation_key', 'string', ['null' => false, 'default' => '', 'limit' => 255]) + ->update(); + $this->table('operational_risks_scales_comments') + ->changeColumn('comment_translation_key', 'string', ['null' => false, 'default' => '', 'limit' => 255]) + ->update(); + + /* Cleanup the table. */ + $this->table('rolf_risks_tags') + ->removeColumn('creator') + ->removeColumn('created_at') + ->removeColumn('updater') + ->removeColumn('updated_at') + ->update(); + + $this->execute( + 'CREATE TABLE IF NOT EXISTS `system_messages` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(11) unsigned NOT NULL, + `title` varchar(255) NOT NULL, + `description` TEXT, + `status` smallint(3) unsigned NOT NULL DEFAULT 1, + `creator` varchar(255) NOT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updater` varchar(255) DEFAULT NULL, + `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + CONSTRAINT `system_messages_user_id_id_fk1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE + );' + ); + $usersQuery = $this->query('SELECT id FROM users WHERE status = 1;'); + foreach ($usersQuery->fetchAll() as $userData) { + $this->table('system_messages')->insert([ + 'user_id' => $userData['id'], + 'title' => 'Monarc version is updated to v2.13.1', + 'description' => 'Please, read the release notes available https://www.monarc.lu/news. In case if you encounter any issues with your analysis, please let us know by sending us an email to info-monarc@nc3.lu.', + 'status' => 1, + 'creator' => 'System', + ])->saveData(); + } + + /* TODO: Should be added to the next release migration, to perform this release in a safe mode. + $this->table('anr_instance_metadata_fields')->removeColumn('label_translation_key')->update(); + $this->table('instances_metadata')->removeColumn('comment_translation_key')->update(); + $this->table('operational_risks_scales_types')->removeColumn('label_translation_key')->update(); + $this->table('operational_risks_scales_comments')->removeColumn('comment_translation_key')->update(); + $this->table('soa_scale_comments')->removeColumn('comment_translation_key')->update(); + $this->table('anrs') + ->removeColumn('label1') + ->removeColumn('label2') + ->removeColumn('label3') + ->removeColumn('label4') + ->removeColumn('description1') + ->removeColumn('description2') + ->removeColumn('description3') + ->removeColumn('description4') + ->update(); + $this->table('recommandations_sets') + ->removeColumn('label1') + ->removeColumn('label2') + ->removeColumn('label3') + ->removeColumn('label4') + ->update(); + $this->table('translations')->drop(); + */ + } +} diff --git a/src/Command/CreateUsersCommand.php b/src/Command/CreateUsersCommand.php index a4b52d44..e664e2c2 100755 --- a/src/Command/CreateUsersCommand.php +++ b/src/Command/CreateUsersCommand.php @@ -2,9 +2,9 @@ namespace Monarc\FrontOffice\Command; -use Monarc\FrontOffice\Model\Entity\User; -use Monarc\FrontOffice\Model\Entity\UserRole; -use Monarc\FrontOffice\Model\Table\UserTable; +use Monarc\FrontOffice\Entity\User; +use Monarc\FrontOffice\Entity\UserRole; +use Monarc\FrontOffice\Table\UserTable; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -14,8 +14,7 @@ class CreateUsersCommand extends Command { protected static $defaultName = 'monarc:create-users'; - /** @var UserTable */ - private $userTable; + private UserTable $userTable; public function __construct(UserTable $userTable) { @@ -58,7 +57,7 @@ protected function execute(InputInterface $input, OutputInterface $output) 'role' => [UserRole::USER_FO], ]); - $this->userTable->saveEntity($user); + $this->userTable->save($user); $output->writeln([ 'FirstName: ' . $user->getFirstname(), diff --git a/src/Command/FixRecommendationsPosition.php b/src/Command/FixRecommendationsPosition.php index 1d90b8cb..b859abd3 100644 --- a/src/Command/FixRecommendationsPosition.php +++ b/src/Command/FixRecommendationsPosition.php @@ -2,8 +2,8 @@ namespace Monarc\FrontOffice\Command; -use Monarc\FrontOffice\Model\Table\AnrTable; -use Monarc\FrontOffice\Model\Table\RecommandationTable; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Table\RecommendationTable; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -16,10 +16,10 @@ class FixRecommendationsPosition extends Command /** @var AnrTable */ private $anrTable; - /** @var RecommandationTable */ + /** @var RecommendationTable */ private $recommendationTable; - public function __construct(AnrTable $anrTable, RecommandationTable $recommendationTable) + public function __construct(AnrTable $anrTable, RecommendationTable $recommendationTable) { $this->anrTable = $anrTable; $this->recommendationTable = $recommendationTable; @@ -43,17 +43,17 @@ protected function execute(InputInterface $input, OutputInterface $output) $recommendationsWithEmptyPosition = $this->recommendationTable->findByAnrWithEmptyPosition($anr); $updatedCount[$anr->getId()] = 0; if (!empty($recommendationsWithEmptyPosition)) { - $maxPosition = $this->recommendationTable->getMaxPositionByAnr($anr); + $maxPosition = $this->recommendationTable->findMaxPosition(['anr' => $anr]); foreach ($recommendationsWithEmptyPosition as $recommendationWithEmptyPosition) { $recommendationWithEmptyPosition->setPosition(++$maxPosition); - $this->recommendationTable->saveEntity($recommendationWithEmptyPosition); + $this->recommendationTable->save($recommendationWithEmptyPosition); $updatedCount[$anr->getId()]++; } } } - $this->recommendationTable->getDb()->flush(); + $this->recommendationTable->flush(); foreach ($updatedCount as $anrId => $count) { $output->writeln(['Anr ID: ' . $anrId . ', updated: ' . $count]); diff --git a/src/Controller/ApiAdminPasswordsController.php b/src/Controller/ApiAdminPasswordsController.php index a65f168e..bf3982c6 100755 --- a/src/Controller/ApiAdminPasswordsController.php +++ b/src/Controller/ApiAdminPasswordsController.php @@ -1,52 +1,52 @@ -passwordService = $passwordService; } + /** + * @param array $data + */ public function create($data) { - //password forgotten + /* Password forgotten. */ if (!empty($data['email']) && empty($data['password'])) { try { $this->passwordService->passwordForgotten($data['email']); - } catch (\Exception $e) { - // Ignore the \Exception: We don't want to leak any data + } catch (\Exception) { + // Ignore the \Exception to avoid the data leak. } } - //verify token + /* Verify token. */ if (!empty($data['token']) && empty($data['password'])) { - $result = $this->passwordService->verifyToken($data['token']); + if ($this->passwordService->verifyToken($data['token'])) { + return $this->getSuccessfulJsonResponse(); + } - return new JsonModel(['status' => $result]); + throw new Exception('The token is not valid or there is a Browser cache issue.', 422); } - //change password not logged + /* Change password not logged. */ if (!empty($data['token']) && !empty($data['password']) && !empty($data['confirm'])) { if ($data['password'] === $data['confirm']) { $this->passwordService->newPasswordByToken($data['token'], $data['password']); @@ -55,6 +55,6 @@ public function create($data) } } - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAdminUsersController.php b/src/Controller/ApiAdminUsersController.php index 978275c4..af638b07 100755 --- a/src/Controller/ApiAdminUsersController.php +++ b/src/Controller/ApiAdminUsersController.php @@ -1,164 +1,101 @@ -createUserInputValidator = $createUserInputValidator; + private UserService $userService; + + private PasswordService $passwordService; + + public function __construct( + GetUsersInputFormatter $getUsersInputFormatter, + PostUserDataInputValidator $postUserDataInputValidator, + UserService $userService, + PasswordService $passwordService + ) { + $this->getUsersInputFormatter = $getUsersInputFormatter; + $this->postUserDataInputValidator = $postUserDataInputValidator; $this->userService = $userService; $this->passwordService = $passwordService; } - /** - * @inheritdoc - */ public function getList() { - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status', 1); - $filterAnd = $status === 'all' - ? null - : ['status' => (int)$status]; - - return new JsonModel(array( - 'count' => $this->userService->getFilteredCount($filter, $filterAnd), - 'users' => $this->userService->getList($page, $limit, $order, $filter, $filterAnd) - )); + $formattedInput = $this->getFormattedInputParams($this->getUsersInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->userService->getCount($formattedInput), + 'users' => $this->userService->getList($formattedInput), + ]); + } + + public function get($id) + { + return $this->getPreparedJsonResponse($this->userService->getCompleteUser((int)$id)); } - /** - * @inheritdoc - */ public function create($data) { - if (!$this->createUserInputValidator->isValid($data)) { - throw new Exception( - 'Data validation errors: [ ' . json_encode($this->createUserInputValidator->getErrorMessages()), - 400 - ); - /* TODO: make it on the application level to throw a particular exception interface and process in Module. - return new JsonModel([ - 'httpStatus' => 400, - 'errors' => $this->createUserInputValidator->getErrorMessages(), - ]);*/ - } - - $this->userService->create($this->createUserInputValidator->getValidData()); - - return new JsonModel(['status' => 'ok']); + /** @var array $data */ + $this->validatePostParams($this->postUserDataInputValidator, $data); + + $this->userService->create($this->postUserDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function update($id, $data) { - // TODO: The request data filtration is responsibility of the sanitization layer + validation should be applied. - // Security: Don't allow changing role, password, status and history fields. To clean later. - if (isset($data['status'])) { - unset($data['status']); - } - if (isset($data['id'])) { - unset($data['id']); - } - if (isset($data['salt'])) { - unset($data['salt']); - } - if (isset($data['updatedAt'])) { - unset($data['updatedAt']); - } - if (isset($data['updater'])) { - unset($data['updater']); - } - if (isset($data['createdAt'])) { - unset($data['createdAt']); - } - if (isset($data['creator'])) { - unset($data['creator']); - } - if (isset($data['dateStart'])) { - unset($data['dateStart']); - } - if (isset($data['dateEnd'])) { - unset($data['dateEnd']); - } - - $this->userService->update($id, $data); - - return new JsonModel(['status' => 'ok']); + /** @var array $data */ + $this->validatePostParams($this->postUserDataInputValidator, $data); + + $this->userService->update((int)$id, $this->postUserDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ - public function get($id) + public function patch($id, $data) { - return new JsonModel($this->userService->getCompleteUser($id)); + /** @var array $data */ + $this->userService->patch((int)$id, $data); + + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function resetPasswordAction() { - $id = $this->params()->fromRoute('id'); + $id = (int)$this->params()->fromRoute('id'); $this->passwordService->resetPassword($id); - return new JsonModel($this->userService->getCompleteUser($id)); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function delete($id) { - $this->userService->delete($id); + $this->userService->delete((int)$id); $this->getResponse()->setStatusCode(204); - return new JsonModel(); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - $this->userService->patch($id, $data); - - return new JsonModel(array('status' => 'ok')); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAdminUsersRightsController.php b/src/Controller/ApiAdminUsersRightsController.php deleted file mode 100755 index 2beb75b4..00000000 --- a/src/Controller/ApiAdminUsersRightsController.php +++ /dev/null @@ -1,43 +0,0 @@ -getService(); - $rights = $service->getMatrix(); - - return new JsonModel($rights); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } -} - diff --git a/src/Controller/ApiAdminUsersRightsControllerFactory.php b/src/Controller/ApiAdminUsersRightsControllerFactory.php deleted file mode 100755 index 4fd2e01d..00000000 --- a/src/Controller/ApiAdminUsersRightsControllerFactory.php +++ /dev/null @@ -1,18 +0,0 @@ -userRoleService = $userRoleService; } - /** - * @inheritdoc - */ public function getList() { $token = $this->getRequest()->getHeader('token'); + if ($token === false) { + throw new Exception\UserNotLoggedInException('The user token is not defined. Please login', 403); + } - $currentUserRoles = $this->userRoleService->getByUserToken($token); + $currentUserRoles = $this->userRoleService->getUserRolesByToken($token->getFieldValue()); - return new JsonModel($currentUserRoles); + return $this->getPreparedJsonResponse($currentUserRoles); } - /** - * @inheritdoc - */ public function get($id) { - $userRoles = $this->userRoleService->getByUserId($id); + $userRoles = $this->userRoleService->getUserRolesByUserId((int)$id); - return new JsonModel([ - 'count' => count($userRoles), + return $this->getPreparedJsonResponse([ + 'count' => \count($userRoles), 'roles' => $userRoles ]); } diff --git a/src/Controller/ApiAnrAbstractController.php b/src/Controller/ApiAnrAbstractController.php index 62afbf8d..43af1545 100755 --- a/src/Controller/ApiAnrAbstractController.php +++ b/src/Controller/ApiAnrAbstractController.php @@ -8,9 +8,10 @@ namespace Monarc\FrontOffice\Controller; use Monarc\Core\Controller\AbstractController; +use Monarc\Core\Controller\Handler\ControllerRequestResponseHandlerTrait; use Monarc\Core\Exception\Exception; use Ramsey\Uuid\Uuid; -use Laminas\View\Model\JsonModel; +use function in_array; /** * Abstract controller for all ANR-based routes. Allows easy permissions filtering for routes below this one. @@ -18,9 +19,8 @@ */ abstract class ApiAnrAbstractController extends AbstractController { - /** - * @inheritdoc - */ + use ControllerRequestResponseHandlerTrait; + public function getList() { $page = $this->params()->fromQuery('page'); @@ -49,9 +49,9 @@ public function getList() } } - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities + $this->name => $entities, ]); } @@ -75,15 +75,11 @@ public function get($id) $entity = $this->getService()->getEntity($identifier); - if (!$entity['anr'] || $entity['anr']->get('id') !== $anrId) { - throw new Exception('Anr ids diffence', 412); - } - if (count($this->dependencies)) { $this->formatDependencies($entity, $this->dependencies); } - return new JsonModel($entity); + return $this->getPreparedJsonResponse($entity); } /** @@ -116,17 +112,20 @@ public function create($data) if (isset($new_data['amv']) && !is_array($new_data['amv'])) { $new_data['amv'] = ['uuid' => $new_data['amv'], 'anr' => $anrId]; } - if (isset($new_data['father']) && isset($new_data['child'])) { + if (isset($new_data['father'], $new_data['child'])) { $new_data['father'] = ['anr' => $anrId, 'uuid' => $new_data['father']]; $new_data['child'] = ['anr' => $anrId, 'uuid' => $new_data['child']]; } + if (isset($new_data['parent'], $new_data['child'])) { + $new_data['parent'] = ['anr' => $anrId, 'uuid' => $new_data['parent']]; + $new_data['child'] = ['anr' => $anrId, 'uuid' => $new_data['child']]; + } $id = $this->getService()->create($new_data); $created_objects[] = $id; } - return new JsonModel([ - 'status' => 'ok', + return $this->getSuccessfulJsonResponse([ 'id' => count($created_objects) == 1 ? $created_objects[0] : $created_objects, ]); } @@ -137,8 +136,14 @@ public function create($data) public function update($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); - $identifier = $this->getService()->get('entity')->getDbAdapter()->getClassMetadata(get_class($this->getService()->get('entity')))->getIdentifierFieldNames(); - if (count($identifier) > 1 && in_array('anr', $identifier) && in_array('uuid', $identifier) && !is_array($id)) { + $identifier = $this->getService()->get('entity')->getDbAdapter()->getClassMetadata( + \get_class($this->getService()->get('entity')) + )->getIdentifierFieldNames(); + if (\count($identifier) > 1 + && in_array('anr', $identifier) + && in_array('uuid', $identifier) + && !is_array($id) + ) { $id = ['uuid' => $id, 'anr' => $anrId]; } if (empty($anrId)) { @@ -148,7 +153,7 @@ public function update($id, $data) $this->getService()->update($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } /** @@ -157,8 +162,14 @@ public function update($id, $data) public function patch($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); - $identifier = $this->getService()->get('entity')->getDbAdapter()->getClassMetadata(get_class($this->getService()->get('entity')))->getIdentifierFieldNames(); - if (count($identifier) > 1 && in_array('anr', $identifier) && in_array('uuid', $identifier) && !is_array($id)) { + $identifier = $this->getService()->get('entity')->getDbAdapter()->getClassMetadata( + \get_class($this->getService()->get('entity')) + )->getIdentifierFieldNames(); + if (\count($identifier) > 1 + && in_array('anr', $identifier) + && in_array('uuid', $identifier) + && !is_array($id) + ) { $id = ['uuid' => $id, 'anr' => $anrId]; } @@ -169,7 +180,7 @@ public function patch($id, $data) $this->getService()->patch($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } /** @@ -177,17 +188,21 @@ public function patch($id, $data) */ public function delete($id) { - $identifier = $this->getService()->get('entity')->getDbAdapter()->getClassMetadata(get_class($this->getService()->get('entity')))->getIdentifierFieldNames(); + $identifier = $this->getService()->get('entity')->getDbAdapter()->getClassMetadata( + \get_class($this->getService()->get('entity')) + )->getIdentifierFieldNames(); $anrId = (int)$this->params()->fromRoute('anrid'); - if (count($identifier) > 1 && in_array('anr', $identifier) && in_array('uuid', $identifier) && !is_array($id)) { + if (\count($identifier) > 1 + && in_array('anr', $identifier) + && in_array('uuid', $identifier) + && !is_array($id) + ) { $id = ['uuid' => $id, 'anr' => $anrId]; } - if ($this->getService()->deleteFromAnr($id, $anrId)) { - return new JsonModel(['status' => 'ok']); - } + $this->getService()->deleteFromAnr($id, $anrId); - return new JsonModel(['status' => 'ok']); // Todo : may be add error message + return $this->getSuccessfulJsonResponse(); } /** @@ -200,19 +215,17 @@ public function deleteList($data) $class = $this->getService()->get('entity'); $entity = new $class(); $ids = $class->getDbAdapter()->getClassMetadata(get_class($entity))->getIdentifierFieldNames(); - if (count($ids) > 1) { + if (\count($ids) > 1) { foreach ($data as $key => $value) { - if (count($ids) > 1 && in_array('anr', $ids) && in_array('uuid', $ids) && !is_array($value)) { + if (in_array('anr', $ids) && in_array('uuid', $ids) && !is_array($value)) { $data[$key] = ['uuid' => $value, 'anr' => $anrId]; } } } - if ($this->getService()->deleteListFromAnr($data, $anrId)) { - return new JsonModel(['status' => 'ok']); - } + $this->getService()->deleteListFromAnr($data, $anrId); - return new JsonModel(['status' => 'ok']); // Todo: may be add error message + return $this->getSuccessfulJsonResponse(); } /** diff --git a/src/Controller/ApiAnrAmvsController.php b/src/Controller/ApiAnrAmvsController.php index f5f3879e..af24654a 100755 --- a/src/Controller/ApiAnrAmvsController.php +++ b/src/Controller/ApiAnrAmvsController.php @@ -1,182 +1,124 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status'); - $asset = $this->params()->fromQuery('asset'); - $amvid = $this->params()->fromQuery('amvid'); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } + $formattedParams = $this->getFormattedInputParams($this->getAmvsInputFormatter); - $filterAnd = ['anr' => $anrId]; + return $this->getPreparedJsonResponse([ + 'count' => $this->anrAmvService->getCount($formattedParams), + 'amvs' => $this->anrAmvService->getList($formattedParams) + ]); + } - if (is_null($status)) { - $status = 1; - } + /** + * @param string $id + */ + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if ($status != 'all') { - $filterAnd['status'] = (int)$status; - } - if ($asset !=null) { - $filterAnd['a.uuid'] = $asset; - $filterAnd['a.anr'] = $anrId; - } + return $this->getPreparedJsonResponse($this->anrAmvService->getAmvData($anr, $id)); + } - if (!empty($amvid)) { - $filterAnd['uuid'] = [ - 'op' => '!=', - 'value' => $amvid, - ]; - } - if($order == 'asset') - $order = 'a.code'; - if($order == '-asset') - $order = '-a.code'; - if($order == 'threat') - $order = 'th.code'; - if($order == '-threat') - $order = '-th.code'; - if($order == 'vulnerability') - $order = 'v.code'; - if($order == '-vulnerability') - $order = '-v.code'; - - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies, 'Monarc\FrontOffice\Model\Entity\Measure', ['referential']); - $this->formatDependencies($entities[$key], $this->dependencies, 'Monarc\FrontOffice\Model\Entity\Threat', ['theme']); - } + + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + if ($this->isBatchData($data)) { + $result = $this->anrAmvService->createAmvItems($anr, $data); + } else { + $this->validatePostParams($this->postAmvDataInputValidator, $data); + $result = $this->anrAmvService->create($anr, $data)->getUuid(); } - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - ]); + return $this->getSuccessfulJsonResponse(['id' => $result]); } /** - * @inheritdoc + * @param string $id + * @param array $data */ - public function get($id) + public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $id = ['uuid'=>$id, 'anr' => $anrId]; - $entity = $this->getService()->getEntity($id); - - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies, 'Monarc\FrontOffice\Model\Entity\Measure', ['referential']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - // Find out the entity's implicitPosition and previous - if ($entity['position'] == 1) { - $entity['implicitPosition'] = 1; - } else { - // We're not at the beginning, get all AMV links of the same asset, and figure out position and previous - $amvsAsset = $this->getService()->getList(1, 0, 'position', null, ['a.anr' => $anrId, 'a.uuid' =>(string)$entity['asset']['uuid']]); - - $i = 0; - foreach ($amvsAsset as $amv) { - if ((string)$amv['uuid'] == (string)$entity['uuid']) { - if ($i == count($amvsAsset) - 1) { - $entity['implicitPosition'] = 2; - } else { - if ($i == 0) { - $entity['implicitPosition'] = 1; - $entity['previous'] = null; - } else { - $entity['implicitPosition'] = 3; - $entity['previous'] = $amvsAsset[$i - 1]; - $this->formatDependencies($entity['previous'], $this->dependencies); - } - } - - break; - } - - ++$i; - } - } + $this->anrAmvService->update($anr, $id, $data); - return new JsonModel($entity); + return $this->getSuccessfulJsonResponse(); } - public function create($data) + /** + * @param string $id + * @param array $data + */ + public function patch($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (!empty($data['measures'])) { - $data['measures'] = $this->addAnrId($data['measures']); - } - unset($data['referential']); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if (array_keys($data) === range(0, \count($data) - 1)) { - /** @var AnrAmvService $anrAmvService */ - $anrAmvService = $this->getService(); - $data = $anrAmvService->createAmvsItems($anrId, $data); + $this->anrAmvService->patch($anr, $id, $data); - if (empty($data)) { - throw new Exception('No new information risks to be imported. Already exist in Knowledge Base', 412); - } - } + return $this->getSuccessfulJsonResponse(); + } + + public function patchList($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrAmvService->createLinkedAmvs($anr, $data['fromReferential'], $data['toReferential']); - return parent::create($data); + return $this->getSuccessfulJsonResponse(); } - public function update($id, $data) + public function delete($id) { - if (count($data['measures']) > 0) { - $data['measures'] = $this->addAnrId($data['measures']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - unset($data ['referential']); + $this->anrAmvService->delete($anr, $id); - return parent::update($id, $data); + return $this->getSuccessfulJsonResponse(); } - public function patchList($data) + public function deleteList($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $service = $this->getService(); - $data['toReferential'] = $this->addAnrId($data['toReferential']); - $service->createLinkedAmvs($data['fromReferential'], $data['toReferential'], $anrId); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'status' => 'ok', - ]); + $this->anrAmvService->deleteList($anr, $data); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrAmvsControllerFactory.php b/src/Controller/ApiAnrAmvsControllerFactory.php deleted file mode 100755 index 0a6a05e6..00000000 --- a/src/Controller/ApiAnrAmvsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getFormattedInputParams($this->getAssetsInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrAssetService->getCount($formattedParams), + 'assets' => $this->anrAssetService->getList($formattedParams), + ]); + } + + /** + * @param string $id + */ + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrAssetService->getAssetData($anr, $id)); + } + + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $isBatchData = $this->isBatchData($data); + $this->validatePostParams( + $this->postAssetDataInputValidator->setIncludeFilter(['anr' => $anr]), + $data, + $isBatchData + ); + + if ($isBatchData) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrAssetService->createList( + $anr, + $this->postAssetDataInputValidator->getValidDataSets() + ), + ]); + } + + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrAssetService->create( + $anr, + $this->postAssetDataInputValidator->getValidData() + )->getUuid(), + ]); + } + + /** + * @param string $id + * @param array $data + */ + public function update($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->validatePostParams( + $this->postAssetDataInputValidator->setIncludeFilter(['anr' => $anr])->setExcludeFilter(['uuid' => $id]), + $data + ); + + $this->anrAssetService->update($anr, $id, $this->postAssetDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param string $id + * @param array $data + */ + public function patch($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrAssetService->patch($anr, $id, $data); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param string $id + */ + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrAssetService->delete($anr, $id); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param array $data + */ + public function deleteList($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrAssetService->deleteList($anr, $data); + + return $this->getSuccessfulJsonResponse(); + } } diff --git a/src/Controller/ApiAnrAssetsControllerFactory.php b/src/Controller/ApiAnrAssetsControllerFactory.php deleted file mode 100755 index c12602a3..00000000 --- a/src/Controller/ApiAnrAssetsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - - /** @var AnrService $service */ - $service = $this->getService(); - $entities = $service->getList($page, $limit, $order, $filter); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel([ - 'count' => count($entities), - $this->name => $entities + $result = $this->anrService->getList(); + + return $this->getPreparedJsonResponse([ + 'count' => \count($result), + 'anrs' => $result, ]); } + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getSuccessfulJsonResponse($this->anrService->getAnrData($anr)); + } + /** - * @inheritdoc + * @param array $data */ public function create($data) { - /** @var AnrService $service */ - $service = $this->getService(); - - if (!isset($data['model'])) { - throw new \Monarc\Core\Exception\Exception('Model missing', 412); - } + $this->validatePostParams($this->createAnrDataInputValidator, $data); - $newAnr = $service->createFromModelToClient($data); + $anr = $this->anrService->createBasedOnModel($this->createAnrDataInputValidator->getValidData()); - return new JsonModel([ - 'status' => 'ok', - 'id' => $newAnr->getId(), - ]); + return $this->getSuccessfulJsonResponse(['id' => $anr->getId()]); } /** - * @inheritdoc + * @param int $id + * @param array $data */ public function patch($id, $data) { - /** @var AnrService $service */ - $service = $this->getService(); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if (isset($data['referentials'])) { - $service->updateReferentials($data); - unset($data['referentials']); - } + $this->anrService->patch($anr, $data); - $service->patch($id, $data); + return $this->getSuccessfulJsonResponse(['id' => $id]); + } - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + public function delete(mixed $id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrService->delete($anr); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrControllerFactory.php b/src/Controller/ApiAnrControllerFactory.php deleted file mode 100755 index a881f999..00000000 --- a/src/Controller/ApiAnrControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -deliverableGenerationService = $deliverableGenerationService; } public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $data['anr'] = $anrId; - - $typeDoc = $data['typedoc']; + $typeDoc = (int)$data['typedoc']; if (empty($typeDoc)) { throw new Exception('Document type missing', 412); } - $params = [ - 'txt' => [ - 'VERSION' => htmlspecialchars($data['version']), - 'STATE' => $data['status'] == 0 ? 'Draft' : 'Final', - 'CLASSIFICATION' => htmlspecialchars($data['classification']), - 'COMPANY' => htmlspecialchars($this->deliverableGenerationService->getCompanyName()), - 'DOCUMENT' => htmlspecialchars($data['docname']), - 'DATE' => date('d/m/Y'), - 'CLIENT' => htmlspecialchars($data['managers']), - 'SMILE' => htmlspecialchars($data['consultants']), - 'SUMMARY_EVAL_RISK' => $data['summaryEvalRisk'] ?? '', - ], - ]; - - // Generate the DOCX file - $filePath = $this->deliverableGenerationService - ->generateDeliverableWithValues($anrId, $typeDoc, $params, $data); - - if (file_exists($filePath)) { - $response = $this->getResponse(); - $response->setContent(file_get_contents($filePath)); - - unlink($filePath); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $headers = $response->getHeaders(); - $headers->clearHeaders() - ->addHeaderLine('Content-Type', 'text/plain; charset=utf-8') - ->addHeaderLine('Content-Disposition', 'attachment; filename="deliverable.docx"'); - - return $this->response; + $filePath = $this->deliverableGenerationService->generateDeliverableWithValues($anr, $typeDoc, $data); + if (!file_exists($filePath)) { + throw new Exception('Generated file is not found: ' . $filePath); } - throw new Exception('Generated file not found: ' . $filePath); - } + $reportContent = file_get_contents($filePath); + $stream = fopen('php://memory', 'rb+'); + fwrite($stream, $reportContent); + rewind($stream); + unlink($filePath); - public function get($id) - { - return new JsonModel([ - 'delivery' => $this->deliverableGenerationService->getLastDeliveries( - (int)$this->params()->fromRoute('anrid'), - $id - ), + return new Response($stream, 200, [ + 'Content-Type' => 'text/plain; charset=utf-8', + 'Content-Length' => strlen($reportContent), + 'Content-Disposition' => 'attachment; filename="deliverable.docx"', ]); } - /** - * @inheritdoc - */ - public function getList() + public function get($id) { - return new JsonModel([ - 'models' => $this->deliverableGenerationService->getDeliveryModels(), - 'delivery' => $this->deliverableGenerationService->getLastDeliveries( - (int)$this->params()->fromRoute('anrid') - ), + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse([ + 'delivery' => $this->deliverableGenerationService->getLastDelivery($anr, (int)$id), ]); } } diff --git a/src/Controller/ApiAnrExportController.php b/src/Controller/ApiAnrExportController.php deleted file mode 100755 index 60fe6be5..00000000 --- a/src/Controller/ApiAnrExportController.php +++ /dev/null @@ -1,56 +0,0 @@ -anrCoreService = $anrCoreService; - } - - public function create($data) - { - if (empty($data['id'])) { - $data['id'] = (int)$this->params()->fromRoute('anrid'); - } - - $output = $this->anrCoreService->exportAnr($data); - - $contentType = 'application/json; charset=utf-8'; - $extension = '.json'; - if (!empty($data['password'])) { - $contentType = 'text/plain; charset=utf-8'; - $extension = '.bin'; - } - - $this->getResponse() - ->getHeaders() - ->clearHeaders() - ->addHeaderLine('Content-Type', $contentType) - ->addHeaderLine('Content-Disposition', 'attachment; filename="' . - (empty($data['filename']) ? $data['id'] : $data['filename']) . $extension . '"'); - - $this->getResponse() - ->setContent($output); - - return $this->getResponse(); - } -} diff --git a/src/Controller/ApiAnrInstancesConsequencesController.php b/src/Controller/ApiAnrInstancesConsequencesController.php index d2bd1a1d..25151dad 100755 --- a/src/Controller/ApiAnrInstancesConsequencesController.php +++ b/src/Controller/ApiAnrInstancesConsequencesController.php @@ -1,33 +1,42 @@ -params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->validatePostParams($this->patchConsequenceDataInputValidator, $data); - $this->getService()->patchConsequence($id, $data); + $this->anrInstanceConsequenceService + ->patchConsequence($anr, (int)$id, $this->patchConsequenceDataInputValidator->getValidData()); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrInstancesConsequencesControllerFactory.php b/src/Controller/ApiAnrInstancesConsequencesControllerFactory.php deleted file mode 100755 index b4e74605..00000000 --- a/src/Controller/ApiAnrInstancesConsequencesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** @var AnrInstanceService $service */ - $service = $this->getService(); - $instances = $service->getInstancesData($anrId); - return new JsonModel([ - $this->name => $instances + $instancesData = $this->anrInstanceService->getInstancesData($anr); + + return $this->getPreparedJsonResponse([ + 'instances' => $instancesData ]); } - /** - * @inheritdoc - */ - public function update($id, $data) + public function get($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** @var AnrInstanceService $service */ - $service = $this->getService(); - $service->updateInstance($anrId, $id, $data); + if ($this->params()->fromQuery('csv', false)) { + return $this->prepareCsvExportResponse( + $this->anrInstanceRiskOpService->getOperationalRisksInCsv($anr, (int)$id, $this->parseParams()) + ); + } + + if ($this->params()->fromQuery('csvInfoInst', false)) { + return $this->prepareCsvExportResponse( + $this->anrInstanceRiskService->getInstanceRisksInCsv($anr, (int)$id, $this->parseParams()) + ); + } - return new JsonModel(['status' => 'ok']); + $instanceData = $this->anrInstanceService->getInstanceData($anr, (int)$id); + + return $this->getPreparedJsonResponse($instanceData); } /** - * @inheritdoc + * Instantiation of an object to the analysis. + * + * @param array $data */ - public function patch($id, $data) + public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** @var AnrInstanceService $service */ - $service = $this->getService(); - $service->patchInstance($anrId, $id, $data, [], false); + $this->validatePostParams($this->createInstanceDataInputValidator, $data); - return new JsonModel(['status' => 'ok']); + $instance = $this->anrInstanceService + ->instantiateObjectToAnr($anr, $this->createInstanceDataInputValidator->getValidData(), true); + + return $this->getSuccessfulJsonResponse(['id' => $instance->getId()]); } /** - * @inheritdoc + * Is called when instances consequences are set (edit impact). + * + * @param array $data */ - public function get($id) + public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - /** @var AnrInstanceService $service */ - $service = $this->getService(); - $entity = $service->getInstanceData($id, $anrId); - - $params = $this->parseParams(); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if ($this->params()->fromQuery('csv', false)) { - // TODO: inject directly here after refactoring. - /** @var AnrInstanceRiskOpService $anrInstanceRiskOpService */ - $anrInstanceRiskOpService = $service->get('instanceRiskOpService'); + $this->validatePostParams($this->updateInstanceDataInputValidator, $data); - return $this->setCsvResponse($anrInstanceRiskOpService->getOperationalRisksInCsv($anrId, $id, $params)); - } - if ($this->params()->fromQuery('csvInfoInst', false)) { - // TODO: inject directly here after refactoring. - /** @var AnrInstanceRiskService $anrInstanceRiskService */ - $anrInstanceRiskService = $service->get('instanceRiskService'); + $this->anrInstanceService + ->updateInstance($anr, (int)$id, $this->updateInstanceDataInputValidator->getValidData()); - return $this->setCsvResponse($anrInstanceRiskService->getInstanceRisksInCsv($anrId, $id, $params)); - } - - if (\count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } - - return new JsonModel($entity); + return $this->getSuccessfulJsonResponse(); } /** - * @inheritdoc + * Is called when we move (drag-n-drop) instance inside of analysis. */ - public function create($data) + public function patch($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - - //verification required - $required = ['object', 'parent', 'position']; - $missing = []; - foreach ($required as $field) { - if (!isset($data[$field])) { - $missing[] = $field . ' missing'; - } - } - if (count($missing)) { - throw new \Monarc\Core\Exception\Exception(implode(', ', $missing), 412); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $data['c'] = isset($data['c']) ? $data['c'] : '-1'; - $data['i'] = isset($data['i']) ? $data['i'] : '-1'; - $data['d'] = isset($data['d']) ? $data['d'] : '-1'; + $this->validatePostParams($this->patchInstanceDataInputValidator, $data); - /** @var AnrInstanceService $service */ - $service = $this->getService(); - $id = $service->instantiateObjectToAnr($anrId, $data, true, true, Instance::MODE_CREA_ROOT); + $this->anrInstanceService + ->patchInstance($anr, (int)$id, $this->patchInstanceDataInputValidator->getValidData()); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(); } - /** - * Helper function to parse query parameters - * @return array The sorted parameters - */ - protected function parseParams() + public function delete($id) { - $keywords = trim($this->params()->fromQuery("keywords", '')); - $kindOfMeasure = $this->params()->fromQuery("kindOfMeasure"); - $order = $this->params()->fromQuery("order", "maxRisk"); - $order_direction = $this->params()->fromQuery("order_direction", "desc"); - $thresholds = $this->params()->fromQuery("thresholds"); - $page = $this->params()->fromQuery("page", 1); - $limit = $this->params()->fromQuery("limit", 50); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return [ - 'keywords' => $keywords, - 'kindOfMeasure' => $kindOfMeasure, - 'order' => $order, - 'order_direction' => $order_direction, - 'thresholds' => $thresholds, - 'page' => $page, - 'limit' => $limit - ]; + $this->anrInstanceService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); } - protected function setCsvResponse(string $content): Response + private function parseParams(): array { - /** @var Response $response */ - $response = $this->getResponse(); - $response->getHeaders()->addHeaderLine('Content-Type', 'text/csv; charset=utf-8'); - $response->setContent($content); + $params = $this->params(); - return $response; + return [ + 'keywords' => trim($params->fromQuery('keywords', '')), + 'kindOfMeasure' => $params->fromQuery('kindOfMeasure'), + 'order' => $params->fromQuery('order', 'maxRisk'), + 'order_direction' => $params->fromQuery('order_direction', 'desc'), + 'thresholds' => $params->fromQuery('thresholds'), + 'page' => (int)$params->fromQuery('page', 1), + 'limit' => (int)$params->fromQuery('limit', 0), + ]; } } diff --git a/src/Controller/ApiAnrInstancesControllerFactory.php b/src/Controller/ApiAnrInstancesControllerFactory.php deleted file mode 100755 index 795ecdde..00000000 --- a/src/Controller/ApiAnrInstancesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getService()->getEntity($data['id']); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - if ($entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids differents', 412); - } - - $output = $this->getService()->export($data); - - if (empty($data['password'])) { - $contentType = 'application/json; charset=utf-8'; - $extension = '.json'; - } else { - $contentType = 'text/plain; charset=utf-8'; - $extension = '.bin'; - } - - $this->getResponse() - ->getHeaders() - ->clearHeaders() - ->addHeaderLine('Content-Type', $contentType) - ->addHeaderLine('Content-Disposition', 'attachment; filename="' . - (empty($data['filename']) ? $data['id'] : $data['filename']) . $extension . '"'); - - $this->getResponse() - ->setContent($output); - - return $this->getResponse(); - } - - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function getList() - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) - { - return $this->methodNotAllowed(); - } -} diff --git a/src/Controller/ApiAnrInstancesExportControllerFactory.php b/src/Controller/ApiAnrInstancesExportControllerFactory.php deleted file mode 100755 index 9327393f..00000000 --- a/src/Controller/ApiAnrInstancesExportControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -anrInstanceMetadataFieldService = $anrInstanceMetadataFieldService; + } + + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $instanceMetadata = $this->anrInstanceMetadataFieldService->create($anr, $data); + + return $this->getSuccessfulJsonResponse(['id' => $instanceMetadata->getId()]); + } + + /** + * @param array $data + */ + public function update($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrInstanceMetadataFieldService->update($anr, (int)$id, $data); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrInstanceMetadataFieldService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiAnrInstancesRisksController.php b/src/Controller/ApiAnrInstancesRisksController.php index 1c64efa5..25ec7784 100755 --- a/src/Controller/ApiAnrInstancesRisksController.php +++ b/src/Controller/ApiAnrInstancesRisksController.php @@ -1,47 +1,80 @@ -validatePostParams($this->postSpecificInstanceRiskDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $instanceRisk = $this->anrInstanceRiskService->createSpecificInstanceRisk( + $anr, + $this->postSpecificInstanceRiskDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(['id' => $instanceRisk->getId()]); + } + public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + /** @var array $data */ + $this->validatePostParams($this->updateInstanceRiskDataInputValidator, $data); - $id = $this->getService()->updateFromRiskTable((int)$id, $data); + /** @var array $data */ + $instanceRisk = $this->anrInstanceRiskService + ->update($anr, (int)$id, $this->updateInstanceRiskDataInputValidator->getValidData()); - $entity = $this->getService()->getEntity($id); + return $this->getPreparedJsonResponse([ + 'id' => $instanceRisk->getId(), + 'threatRate' => $instanceRisk->getThreatRate(), + 'vulnerabilityRate' => $instanceRisk->getVulnerabilityRate(), + 'reductionAmount' => $instanceRisk->getReductionAmount(), + 'riskConfidentiality' => $instanceRisk->getRiskConfidentiality(), + 'riskIntegrity' => $instanceRisk->getRiskIntegrity(), + 'riskAvailability' => $instanceRisk->getRiskAvailability(), + 'cacheMaxRisk' => $instanceRisk->getCacheMaxRisk(), + 'cacheTargetedRisk' => $instanceRisk->getCacheTargetedRisk(), + ]); + } - if (count($this->dependencies)) { - foreach ($this->dependencies as $d) { - unset($entity[$d]); - } - } + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrInstanceRiskService->delete($anr, (int)$id); - return new JsonModel($entity); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrInstancesRisksControllerFactory.php b/src/Controller/ApiAnrInstancesRisksControllerFactory.php deleted file mode 100755 index f8128ddb..00000000 --- a/src/Controller/ApiAnrInstancesRisksControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -anrInstanceRiskOpService = $anrInstanceRiskOpService; + $this->validatePostParams($this->postSpecificInstanceRiskOpDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $operationalInstanceRisk = $this->anrInstanceRiskOpService->createSpecificOperationalInstanceRisk( + $anr, + $this->postSpecificInstanceRiskOpDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(['id' => $operationalInstanceRisk->getId()]); } + /** + * @param array $data + */ public function update($id, $data) { - $risk = $this->anrInstanceRiskOpService->update((int)$id, $data); - unset($risk['anr'], $risk['instance'], $risk['object'], $risk['rolfRisk']); + $this->validatePostParams($this->updateInstanceRiskOpDataInputValidator, $data); - return new JsonModel($risk); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $instanceRiskOp = $this->anrInstanceRiskOpService->update( + $anr, + (int)$id, + $this->updateInstanceRiskOpDataInputValidator->getValidData() + ); + return $this->getPreparedJsonResponse([ + 'cacheBrutRisk' => $instanceRiskOp->getCacheBrutRisk(), + 'cacheNetRisk' => $instanceRiskOp->getCacheNetRisk(), + 'cacheTargetedRisk' => $instanceRiskOp->getCacheTargetedRisk(), + ]); + } + /** + * @param array $data + */ public function patch($id, $data) { - $risk = $this->anrInstanceRiskOpService->updateScaleValue((int)$id, $data); - unset($risk['anr'], $risk['instance'], $risk['object'], $risk['rolfRisk']); + $this->validatePostParams($this->patchInstanceRiskOpDataInputValidator, $data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $instanceRiskOp = $this->anrInstanceRiskOpService->updateScaleValue( + $anr, + (int)$id, + $this->patchInstanceRiskOpDataInputValidator->getValidData() + ); + + return $this->getPreparedJsonResponse([ + 'cacheBrutRisk' => $instanceRiskOp->getCacheBrutRisk(), + 'cacheNetRisk' => $instanceRiskOp->getCacheNetRisk(), + 'cacheTargetedRisk' => $instanceRiskOp->getCacheTargetedRisk(), + ]); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrInstanceRiskOpService->delete($anr, (int)$id); - return new JsonModel($risk); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrInterviewsController.php b/src/Controller/ApiAnrInterviewsController.php index 81b851e3..22017799 100755 --- a/src/Controller/ApiAnrInterviewsController.php +++ b/src/Controller/ApiAnrInterviewsController.php @@ -1,21 +1,22 @@ -params()->fromRoute('anrid'); - - $data['anr'] = $anrId; - - /** @var AnrObjectCategoryService $service */ - $service = $this->getService(); - $service->patchLibraryCategory($id, $data); - - return new JsonModel(['status' => 'ok']); - } - - /** - * @inheritdoc - */ - public function getList() - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function create($data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) - { - return $this->methodNotAllowed(); - } -} diff --git a/src/Controller/ApiAnrLibraryCategoryControllerFactory.php b/src/Controller/ApiAnrLibraryCategoryControllerFactory.php deleted file mode 100755 index dd801c7b..00000000 --- a/src/Controller/ApiAnrLibraryCategoryControllerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - /** @var AnrObjectService $service */ - $service = $this->getService(); - $objectsCategories = $service->getCategoriesLibraryByAnr($anrId); - - $this->formatDependencies($objectsCategories, $this->dependencies); - - $fields = ['id', 'label1', 'label2', 'label3', 'label4', 'position', 'objects', 'child']; - $objectsCategories = $this->recursiveArray($objectsCategories, null, 0, $fields); - - return new JsonModel([ - $this->name => $objectsCategories - ]); } - /** - * @inheritdoc - */ - public function create($data) - { - $anrId = $this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - if (!isset($data['objectId'])) { - throw new \Monarc\Core\Exception\Exception('objectId is missing'); - } - - /** @var AnrObjectService $service */ - $service = $this->getService(); - $id = $service->attachObjectToAnr($data['objectId'], $anrId, null, null, AbstractEntity::FRONT_OFFICE); - - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); - } - - /** - * @inheritdoc - */ - public function delete($id) - { - $anrId = $this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - /** @var AnrObjectService $service */ - $service = $this->getService(); - $service->detachObjectToAnr($id, $anrId); - - return new JsonModel([ - 'status' => 'ok' - ]); - } - - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) + public function getList() { - return $this->methodNotAllowed(); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** - * @inheritdoc - */ - public function patch($id, $data) - { - return $this->methodNotAllowed(); + return $this->getPreparedJsonResponse(['categories' => $this->anrObjectService->getLibraryTreeStructure($anr)]); } } diff --git a/src/Controller/ApiAnrLibraryControllerFactory.php b/src/Controller/ApiAnrLibraryControllerFactory.php deleted file mode 100755 index 2605454b..00000000 --- a/src/Controller/ApiAnrLibraryControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status'); - $referential = $this->params()->fromQuery('referential'); - $category = $this->params()->fromQuery('category'); - $anrId = (int)$this->params()->fromRoute('anrid'); - - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - $filterAnd = []; - $filterJoin[] = ['as' => 'r','rel' => 'referential']; //make a join because composite key are not supported - - if (is_null($status)) { - $status = 1; - } - $filterAnd = ($status == "all") ? null : ['status' => (int) $status] ; - - $filterAnd = ['anr' => $anrId]; + $formattedParams = $this->getFormattedInputParams($this->getMeasuresInputFormatter); - if ($referential) { - $filterAnd['r.anr']=$anrId; - $filterAnd['r.uuid']= $referential; - } - if ($category) { - $filterAnd['category'] = (int)$category; - } - - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel(array( - 'count' => $service->getFilteredCount($filter, $filterAnd, $filterJoin), - $this->name => $entities - )); + return $this->getPreparedJsonResponse([ + 'count' => $this->anrMeasureService->getCount($formattedParams), + 'measures' => $this->anrMeasureService->getList($formattedParams), + ]); } - public function update($id, $data) + /** + * @param string $id + */ + public function get($id) { - unset($data['rolfRisks']); // not managed for the moement - $anrId = (int)$this->params()->fromRoute('anrid'); - $ids = ['anr'=>$anrId,'uuid'=>$data['uuid']]; - $data['anr'] = $anrId; - $data ['referential'] = ['anr' => $anrId, 'uuid' => $data['referential']]; //all the objects is send but we just need the uuid - $data['category'] ['referential'] = $data ['referential']; - unset($data['measuresLinked']); - unset($data['amvs']); - return parent::update($ids, $data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - } - - public function patch($id, $data) - { - unset($data['measures']); - return parent::patch($id, $data); + return $this->getPreparedJsonResponse($this->anrMeasureService->getMeasureData($anr, $id)); } public function create($data) { - unset($data['rolfRisks']); // not managed for the moement + $isBatchData = $this->isBatchData($data); + $this->validatePostParams($this->postMeasureDataInputValidator, $data, $isBatchData); - unset($data['measuresLinked']); - unset($data['amvs']); - return parent::create($data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + if ($this->isBatchData($data)) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrMeasureService + ->createList($anr, $this->postMeasureDataInputValidator->getValidDataSets()), + ]); + } + + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrMeasureService + ->create($anr, $this->postMeasureDataInputValidator->getValidData())->getUuid(), + ]); } /** - * @inheritdoc + * @param string $id + * @param array $data */ - public function get($id) + public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $ids = ['uuid'=>$id,'anr'=>$anrId]; - return parent::get($ids); + $this->validatePostParams($this->updateMeasureDataInputValidator->setExcludeFilter(['uuid' => $id]), $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrMeasureService->update($anr, $id, $this->updateMeasureDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); } /** - * @inheritdoc + * @param string $id */ public function delete($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $ids = ['uuid'=>$id,'anr'=>$anrId]; - return parent::delete($ids); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrMeasureService->delete($anr, $id); + + return $this->getSuccessfulJsonResponse(); } public function deleteList($data) { - $new_data = []; - $anrId = (int)$this->params()->fromRoute('anrid'); - foreach ($data as $uuid) { - $new_data[] = ['uuid' => $uuid, 'anr'=>$anrId]; - } - return parent::deleteList($new_data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrMeasureService->deleteList($anr, $data); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrMeasuresControllerFactory.php b/src/Controller/ApiAnrMeasuresControllerFactory.php deleted file mode 100755 index 5a50dec4..00000000 --- a/src/Controller/ApiAnrMeasuresControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getRequest()->getAttribute('anr'); + $measuresLinksData = $this->anrMeasureLinkService->getList($anr); + + return $this->getPreparedJsonResponse([ + 'count' => \count($measuresLinksData), + 'measuresLinks' => $measuresLinksData, + ]); + } + + public function create($data) + { + $isBatchData = $this->isBatchData($data); + $this->validatePostParams($this->postMeasureLinkDataInputValidator, $data, $isBatchData); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + if ($this->isBatchData($data)) { + $this->anrMeasureLinkService->createList( + $anr, + $this->postMeasureLinkDataInputValidator->getValidDataSets() + ); + } else { + $this->anrMeasureLinkService->create($anr, $this->postMeasureLinkDataInputValidator->getValidData()); + } + + return $this->getSuccessfulJsonResponse(); + } + + public function deleteList($data) + { + $masterMeasureUuid = $this->params()->fromQuery('masterMeasureUuid'); + $linkedMeasureUuid = $this->params()->fromQuery('linkedMeasureUuid'); + $this->validatePostParams( + $this->postMeasureLinkDataInputValidator, + compact('masterMeasureUuid', 'linkedMeasureUuid') + ); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrMeasureLinkService->delete($anr, $masterMeasureUuid, $linkedMeasureUuid); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiAnrMeasuresMeasuresController.php b/src/Controller/ApiAnrMeasuresMeasuresController.php deleted file mode 100644 index 30286b5b..00000000 --- a/src/Controller/ApiAnrMeasuresMeasuresController.php +++ /dev/null @@ -1,75 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $fatherId = $this->params()->fromQuery('fatherId'); - $childId = $this->params()->fromQuery('childId'); - $filterAnd = ['anr' => $anrId]; - - if ($fatherId) { - $filterAnd['father'] = $fatherId; - } - if ($childId) { - $filterAnd['child'] = $childId; - } - - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel(array( - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - )); - } - - public function deleteList($data) - { - if (empty($data)) { //we delete one measuremeasure - $anrId = (int)$this->params()->fromRoute('anrid'); - $fatherId = $this->params()->fromQuery('father'); - $childId = $this->params()->fromQuery('child'); - - $this->getService()->delete(['anr' => $anrId, 'father' => $fatherId, 'child' => $childId]); - - return new JsonModel(['status' => 'ok']); - } - - return parent::deleteList($data); - } -} diff --git a/src/Controller/ApiAnrMeasuresMeasuresControllerFactory.php b/src/Controller/ApiAnrMeasuresMeasuresControllerFactory.php deleted file mode 100644 index 3bef2f27..00000000 --- a/src/Controller/ApiAnrMeasuresMeasuresControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -anrMetadatasOnInstancesService = $anrMetadatasOnInstancesService; - } - - public function create($data) - { - $anrId = (int) $this->params()->fromRoute('anrid'); - return new JsonModel([ - 'status' => 'ok', - 'id' => $this->anrMetadatasOnInstancesService->createAnrMetadatasOnInstances($anrId, $data), - ]); - } - - public function getList() - { - $anrId = (int) $this->params()->fromRoute('anrid'); - $language = $this->params()->fromQuery("language"); - - return new JsonModel([ - 'data' => $this->anrMetadatasOnInstancesService->getAnrMetadatasOnInstances($anrId, $language), - ]); - } - - public function delete($id) - { - $this->anrMetadatasOnInstancesService->deleteMetadataOnInstances($id); - - return new JsonModel(['status' => 'ok']); - } - - public function get($id) - { - $anrId = (int) $this->params()->fromRoute('anrid'); - $language = $this->params()->fromQuery("language"); - return new JsonModel([ - 'data' => $this->anrMetadatasOnInstancesService->getAnrMetadataOnInstance($anrId, $id, $language), - ]); - } - - public function update($id, $data) - { - if ($this->anrMetadatasOnInstancesService->update((int)$id, $data)) { - return new JsonModel(['status' => 'ok']); - } - - return new JsonModel(['status' => 'ko']); - } -} diff --git a/src/Controller/ApiAnrObjectController.php b/src/Controller/ApiAnrObjectController.php deleted file mode 100755 index 6d7a1fe7..00000000 --- a/src/Controller/ApiAnrObjectController.php +++ /dev/null @@ -1,79 +0,0 @@ -getEvent()->getRouteMatch(); - return new JsonModel($this->getService()->getParents($matcher->getParam('anrid'), $matcher->getParam('id'))); - } - - /** - * @inheritdoc - */ - public function getList() - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function get($id) - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function create($data) - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - $this->methodNotAllowed(); - } -} diff --git a/src/Controller/ApiAnrObjectControllerFactory.php b/src/Controller/ApiAnrObjectControllerFactory.php deleted file mode 100755 index cb36a89a..00000000 --- a/src/Controller/ApiAnrObjectControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - if (empty($order)) { - $order = "position"; - } - $filter = $this->params()->fromQuery('filter'); - $lock = $this->params()->fromQuery('lock') == "false" ? false : true; - - /** @var AnrObjectCategoryService $service */ - $service = $this->getService(); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $filterAnd = ['anr' => $anrId]; - $catid = (int)$this->params()->fromQuery('catid'); - $parentId = (int)$this->params()->fromQuery('parentId'); - if (!empty($catid)) { - $filterAnd['id'] = [ - 'op' => 'NOT IN', - 'value' => [$catid], - ]; - if ($parentId > 0) { - $filterAnd['id']['value'][] = $parentId; - $filterAnd['parent'] = $parentId; - } else { - $filterAnd['parent'] = null; - } - } elseif ($parentId > 0) { - $filterAnd['parent'] = $parentId; - } elseif (!$lock) { - $filterAnd['parent'] = null; - } - - $objectCategories = $service->getListSpecific($page, $limit, $order, $filter, $filterAnd); - - $fields = ['id', 'label1', 'label2', 'label3', 'label4', 'position']; - - if ($parentId > 0 && $lock) { - $recursiveArray = $this->getCleanFields($objectCategories, $fields); - } else { - $recursiveArray = $this->recursiveArray($objectCategories, null, 0, $fields); - } - - return new JsonModel([ - 'count' => $this->getService()->getFilteredCount($filter, $filterAnd), - $this->name => $recursiveArray + $formattedParams = $this->getFormattedInputParams($this->objectCategoriesInputFormatter); + $this->objectCategoriesInputFormatter->prepareCategoryFilter(); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrObjectCategoryService->getCount($formattedParams), + 'categories' => $this->anrObjectCategoryService->getList($formattedParams), ]); } + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrObjectCategoryService->getObjectCategoryData($anr, (int)$id)); + } + /** - * Helper method that cleans up an entity by only keeping the fields that are listed in the $fields parameter - * @param array $items The items to filter - * @param array $fields The fields to keep - * @return array The filtered items + * @param array $data */ - public function getCleanFields($items, $fields) + public function create($data) { - $output = []; - foreach ($items as $item) { - $item_output = []; - - foreach ($item as $key => $value) { - if (in_array($key, $fields)) { - $item_output[$key] = $value; - } - } - - $output[] = $item_output; - } - return $output; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $category = $this->anrObjectCategoryService->create($anr, $data); + + return $this->getSuccessfulJsonResponse(['categ' => ['id' => $category->getId()]]); } /** - * @inheritdoc + * @param array $data */ - public function create($data) + public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; + $this->validatePostParams($this->postObjectCategoryDataInputValidator, $data); - $obj = $this->getService()->create($data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'status' => 'ok', - 'categ' => $obj, - ]); + $this->anrObjectCategoryService->update($anr, (int)$id, $data); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrObjectCategoryService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrObjectsCategoriesControllerFactory.php b/src/Controller/ApiAnrObjectsCategoriesControllerFactory.php deleted file mode 100755 index 79d7d741..00000000 --- a/src/Controller/ApiAnrObjectsCategoriesControllerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -anrObjectService = $anrObjectService; + $this->objectImportService = $objectImportService; + $this->getObjectsInputFormatter = $getObjectsInputFormatter; + $this->getObjectInputFormatter = $getObjectInputFormatter; + $this->postObjectDataInputValidator = $postObjectDataInputValidator; + } - /** - * @inheritdoc - */ public function getList() { - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $asset = (int)$this->params()->fromQuery('asset'); - $category = (int)$this->params()->fromQuery('category'); - $lock = $this->params()->fromQuery('lock'); - $anr = (int)$this->params()->fromRoute('anrid'); - - /** @var ObjectService $service */ - $service = $this->getService(); - $objects = $service->getListSpecific($page, $limit, $order, $filter, $asset, $category, null, $anr, $lock); - - if ($lock == 'true') { - foreach ($objects as $key => $object) { - $this->formatDependencies($objects[$key], $this->dependencies); - } - } + $formattedInputParams = $this->getFormattedInputParams($this->getObjectsInputFormatter); - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $asset, $category, null, $anr), - $this->name => $objects, + return $this->getPreparedJsonResponse([ + 'count' => $this->anrObjectService->getCount($formattedInputParams), + 'objects' => $this->anrObjectService->getList($formattedInputParams), ]); } /** - * @inheritdoc + * @param string $id */ public function get($id) { - $anr = (int)$this->params()->fromRoute('anrid'); - - /** @var ObjectService $service */ - $service = $this->getService(); - $object = $service->getCompleteEntity($id, MonarcObject::CONTEXT_ANR, $anr); - - if (count($this->dependencies)) { - $this->formatDependencies($object, $this->dependencies); - } - - $anrs = []; - foreach ($object['anrs'] as $key => $anr) { - $anrs[] = $anr->getJsonArray(); - } - $object['anrs'] = $anrs; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $formattedInputParams = $this->getFormattedInputParams($this->getObjectInputFormatter); - return new JsonModel($object); + return $this->getPreparedJsonResponse($this->anrObjectService->getObjectData($anr, $id, $formattedInputParams)); } /** - * @inheritdoc + * @param array $data */ public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - if (array_keys($data) !== range(0, count($data) - 1)) { - # if $data is an associative array - $data = array($data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + if (!empty($data['mosp'])) { + $monarcObject = $this->objectImportService->importFromArray($anr, $data); + + return $monarcObject !== null + ? $this->getSuccessfulJsonResponse(['id' => $monarcObject->getUuid()]) + : $this->getSuccessfulJsonResponse(); } - $created_objects = array(); - foreach ($data as $key => $new_data) { - $new_data['anr'] = $anrId; - if (\is_string($new_data['asset'])) { - $new_data['asset'] = ['uuid' => $new_data['asset'], 'anr' => $anrId]; - } - $id = $this->getService()->create($new_data, true, AbstractEntity::FRONT_OFFICE); - array_push($created_objects, $id); - } - return new JsonModel([ - 'status' => 'ok', - 'id' => count($created_objects)==1 ? $created_objects[0]: $created_objects, - ]); - } + $isBatchData = $this->isBatchData($data); + $this->validatePostParams($this->postObjectDataInputValidator, $data, $isBatchData); + + $result = $isBatchData + ? $this->anrObjectService->createList($anr, $this->postObjectDataInputValidator->getValidDataSets()) + : $this->anrObjectService->create($anr, $this->postObjectDataInputValidator->getValidData()); + return $this->getSuccessfulJsonResponse(['id' => $isBatchData ? $result : $result->getUuid()]); + } /** - * @inheritdoc + * @param string $id + * @param array $data */ public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** @var ObjectService $service */ - $service = $this->getService(); - $service->update($id, $data, AbstractEntity::FRONT_OFFICE); + $this->validatePostParams($this->postObjectDataInputValidator, $data); - return new JsonModel(['status' => 'ok']); + $this->anrObjectService->update($anr, $id, $this->postObjectDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); } /** - * @inheritdoc + * @param string $id */ - public function patch($id, $data) + public function delete($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrObjectService->delete($anr, $id); + + return $this->getSuccessfulJsonResponse(); + } - /** @var ObjectService $service */ - $service = $this->getService(); - $service->patch($id, $data, AbstractEntity::FRONT_OFFICE); + /** + * Called to validate the library objects detaching possibility. + */ + public function parentsAction() + { + $anr = $this->getRequest()->getAttribute('anr'); + $objectUuid = $this->params()->fromRoute('id'); - return new JsonModel(['status' => 'ok']); + return $this->getPreparedJsonResponse($this->anrObjectService->getParentsInAnr($anr, $objectUuid)); } } diff --git a/src/Controller/ApiAnrObjectsControllerFactory.php b/src/Controller/ApiAnrObjectsControllerFactory.php deleted file mode 100755 index 1b796029..00000000 --- a/src/Controller/ApiAnrObjectsControllerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -params()->fromRoute('anrid'); - if (!empty($anrId)) { - $data['anr'] = $anrId; - } - if (isset($data['id'])) { - $id = $this->getService()->duplicate($data, AbstractEntity::FRONT_OFFICE); + use ControllerRequestResponseHandlerTrait; - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); - } else { - throw new \Monarc\Core\Exception\Exception('Object to duplicate is required'); - } - } - - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); + public function __construct( + private AnrObjectService $anrObjectService, + private DuplicateObjectDataInputValidator $duplicateObjectDataInputValidator + ) { } - /** - * @inheritdoc - */ - public function getList() + public function create($data) { - return $this->methodNotAllowed(); - } + $this->validatePostParams($this->duplicateObjectDataInputValidator, $data); - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** - * @inheritdoc - */ - public function patch($id, $data) - { - return $this->methodNotAllowed(); - } + $object = $this->anrObjectService->duplicate($anr, $this->duplicateObjectDataInputValidator->getValidData()); - /** - * @inheritdoc - */ - public function delete($id) - { - return $this->methodNotAllowed(); + return $this->getSuccessfulJsonResponse(['id' => $object->getUuid()]); } } diff --git a/src/Controller/ApiAnrObjectsDuplicationControllerFactory.php b/src/Controller/ApiAnrObjectsDuplicationControllerFactory.php deleted file mode 100755 index aa16b910..00000000 --- a/src/Controller/ApiAnrObjectsDuplicationControllerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - $entity = $this->getService()->getEntity(['uuid' => $data['id'], 'anr' => $anrId]); - - if ($entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids differents', 412); - } - $data['anr'] = $anrId; - $output = $this->getService()->export($data); - - $response = $this->getResponse(); - $response->setContent($output); - - $headers = $response->getHeaders(); - $filename = empty($data['filename']) ? $data['id'] : $data['filename']; - $headers->clearHeaders() - ->addHeaderLine('Content-Type', 'application/json; charset=utf-8') - ->addHeaderLine('Content-Disposition', 'attachment; filename="' . $filename . '.json"'); - - return $this->response; - } - - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function getList() - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) - { - return $this->methodNotAllowed(); - } -} diff --git a/src/Controller/ApiAnrObjectsExportControllerFactory.php b/src/Controller/ApiAnrObjectsExportControllerFactory.php deleted file mode 100755 index b4936023..00000000 --- a/src/Controller/ApiAnrObjectsExportControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -anrObjectService = $anrObjectService; - } - - public function getList() - { - $anrId = (int)$this->params()->fromRoute('anrid'); - $filter = $this->params()->fromQuery("filter"); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - $objects = $this->anrObjectService->getCommonObjects($anrId, $filter); - - return new JsonModel([ - 'count' => \count($objects), - 'objects' => $objects, - ]); - } - - public function get($id) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - $object = $this->anrObjectService->getCommonEntity($anrId, $id); - - return new JsonModel($object); - } - - public function create($data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - $files = $this->params()->fromFiles('file'); - if (empty($files)) { - throw new Exception('File missing', 412); - } - $data['file'] = $files; - - [$ids, $errors] = $this->anrObjectService->importFromFile($anrId, $data); - - return new JsonModel([ - 'status' => 'ok', - 'id' => $ids, - 'errors' => $errors, - ]); - } - - public function patch($id, $data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - $monarcObject = $this->anrObjectService->importFromCommon($id, $data); - if ($monarcObject === null) { - throw new Exception('An error occurred during the import of the object.', 412); - } - - return new JsonModel([ - 'status' => 'ok', - 'id' => $monarcObject->getUuid(), - ]); - } -} diff --git a/src/Controller/ApiAnrObjectsObjectsController.php b/src/Controller/ApiAnrObjectsObjectsController.php index 1e4c1bce..5ae26c77 100755 --- a/src/Controller/ApiAnrObjectsObjectsController.php +++ b/src/Controller/ApiAnrObjectsObjectsController.php @@ -1,82 +1,74 @@ -getService(); - $service->moveObject($id, $data['move']); - } + use ControllerRequestResponseHandlerTrait; - return new JsonModel(['status' => 'ok']); + public function __construct( + private AnrObjectObjectService $anrObjectObjectService, + private CreateDataInputValidator $createDataInputValidator, + private MovePositionDataInputValidator $movePositionDataInputValidator + ) { } /** - * @inheritdoc + * @param array $data */ public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - $data['child'] = ['anr' => $anrId, 'uuid' => $data['child']]; - $data['father'] = ['anr' => $anrId, 'uuid' => $data['father']]; + $this->validatePostParams($this->createDataInputValidator, $data); - $id = $this->getService()->create($data, true, AbstractEntity::FRONT_OFFICE); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); - } + $objectComposition = $this->anrObjectObjectService->create( + $anr, + $this->createDataInputValidator->getValidData() + ); - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); + return $this->getSuccessfulJsonResponse(['id' => $objectComposition->getId()]); } /** - * @inheritdoc + * @param array $data */ - public function getList() + public function update($id, $data) { - return $this->methodNotAllowed(); + $this->validatePostParams($this->movePositionDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrObjectObjectService->shiftPositionInComposition( + $anr, + (int)$id, + $this->movePositionDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ - public function patch($id, $data) + public function delete($id) { - return $this->methodNotAllowed(); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrObjectObjectService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrObjectsObjectsControllerFactory.php b/src/Controller/ApiAnrObjectsObjectsControllerFactory.php deleted file mode 100755 index 56696246..00000000 --- a/src/Controller/ApiAnrObjectsObjectsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $this->getService()->replaceList($data, $anrId); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrQuestionsChoicesControllerFactory.php b/src/Controller/ApiAnrQuestionsChoicesControllerFactory.php deleted file mode 100755 index 04bbc9f7..00000000 --- a/src/Controller/ApiAnrQuestionsChoicesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status', 1); - $recommandationSet = $this->params()->fromQuery('recommandationSet'); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - $filterAnd = ['anr' => $anrId]; - - if ($status !== 'all') { - $filterAnd['status'] = $status; - } - - if (!is_null($recommandationSet)) { - $filterAnd['r.uuid'] = $recommandationSet; - $filterAnd['r.anr'] = $anrId; - } - - /** @var AnrRecommandationService $service */ - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - ]); - } - - public function update($id, $data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - if (!isset($data['anr'])) { - $data['anr'] = $anrId; - } - - $this->getService()->update($id, $data); - - return new JsonModel(['status' => 'ok']); - } - - public function patch($id, $data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - if (!isset($data['anr'])) { - $data['anr'] = $anrId; - } - - $this->getService()->patch($id, $data); - - return new JsonModel(['status' => 'ok']); - } - - /** - * @inheritdoc - */ - public function create($data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - if (array_keys($data) !== range(0, count($data) - 1)) { - # if $data is an associative array - $data = array($data); - } - $created_recommendations = []; - - foreach ($data as $key => $new_data) { - $new_data['anr'] = $anrId; - $created_recommendations[] = $this->getService()->create($new_data); - } - return new JsonModel([ - 'status' => 'ok', - 'id' => count($created_recommendations)==1 ? $created_recommendations[0]: $created_recommendations, - ]); - } -} diff --git a/src/Controller/ApiAnrRecommandationsControllerFactory.php b/src/Controller/ApiAnrRecommandationsControllerFactory.php deleted file mode 100755 index 7a479b07..00000000 --- a/src/Controller/ApiAnrRecommandationsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status'); - $risk = $this->params()->fromQuery('risk'); - $recommandation = $this->params()->fromQuery('recommandation'); - $op = $this->params()->fromQuery('op'); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - $filterAnd = ['anr' => $anrId]; - - if (!is_null($status) && $status != 'all') { - $filterAnd['status'] = $status; - } - - if (!is_null($risk)) { - $fieldName = ($op) ? 'instanceRiskOp' : 'instanceRisk'; - $filterAnd[$fieldName] = intval($risk); - } - - if (!is_null($recommandation)) { - $filterAnd['r.uuid'] = $recommandation; - $filterAnd['r.anr'] = $anrId; - } - - /** @var AnrRecommandationRiskService $service */ - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies, 'Monarc\FrontOffice\Model\Entity\Recommandation', ['recommandationSet']); - $this->formatDependencies($entities[$key], $this->dependencies, 'Monarc\FrontOffice\Model\Entity\Instance', ['object']); - } - } - - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - ]); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } -} diff --git a/src/Controller/ApiAnrRecommandationsRisksControllerFactory.php b/src/Controller/ApiAnrRecommandationsRisksControllerFactory.php deleted file mode 100755 index c2e528d4..00000000 --- a/src/Controller/ApiAnrRecommandationsRisksControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - /** @var AnrRecommandationRiskService $service */ - $service = $this->getService(); - $service->validateFor($id, $data); - - return new JsonModel(['status' => 'ok']); - } - - /** - * @inheritdoc - */ - public function create($data) - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function getList() - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } -} diff --git a/src/Controller/ApiAnrRecommandationsRisksValidateControllerFactory.php b/src/Controller/ApiAnrRecommandationsRisksValidateControllerFactory.php deleted file mode 100755 index b6aedb89..00000000 --- a/src/Controller/ApiAnrRecommandationsRisksValidateControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - - $filterAnd = ['anr' => $anrId]; - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel(array( - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - )); - } - - public function get($id) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - $entity = $this->getService()->getEntity(['anr' => $anrId, 'uuid' => $id]); - - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids diffence', 412); - } - - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } - - return new JsonModel($entity); - } - - public function update($id, $data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - $newId = ['anr'=> $anrId, 'uuid' => $data['uuid']]; - - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - $this->getService()->update($newId, $data); - - return new JsonModel(['status' => 'ok']); - } - - public function delete($id) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - $newId = ['anr'=> $anrId, 'uuid' => $id]; - - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - $this->getService()->delete($newId); - - return new JsonModel(['status' => 'ok']); - } -} diff --git a/src/Controller/ApiAnrRecommandationsSetsControllerFactory.php b/src/Controller/ApiAnrRecommandationsSetsControllerFactory.php deleted file mode 100644 index c9eeecd5..00000000 --- a/src/Controller/ApiAnrRecommandationsSetsControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -getFormattedInputParams($this->getRecommendationsInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrRecommendationService->getCount($formattedParams), + 'recommendations' => $this->anrRecommendationService->getList($formattedParams) + ]); + } + + /** + * @param string $id + */ + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrRecommendationService->getRecommendationData($anr, $id)); + } + + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $isBatchData = $this->isBatchData($data); + $this->validatePostParams( + $this->postRecommendationDataInputValidator->setIncludeFilter(['anr' => $anr]), + $data, + $isBatchData + ); + + $result = $isBatchData ? $this->anrRecommendationService->createList( + $anr, + $this->postRecommendationDataInputValidator->getValidDataSets() + ) : $this->anrRecommendationService->create( + $anr, + $this->postRecommendationDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(['id' => $isBatchData ? $result : $result->getUuid()]); + } + + /** + * @param string $id + * @param array $data + */ + public function patch($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->validatePostParams( + $this->patchRecommendationDataInputValidator + ->setIncludeFilter(['anr' => $anr]) + ->setExcludeFilter(['uuid' => $id]), + $data + ); + + $this->anrRecommendationService->patch($anr, $id, $this->patchRecommendationDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param string $id + */ + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrRecommendationService->delete($anr, $id); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiAnrRecommendationsHistoryController.php b/src/Controller/ApiAnrRecommendationsHistoryController.php new file mode 100755 index 00000000..89582df9 --- /dev/null +++ b/src/Controller/ApiAnrRecommendationsHistoryController.php @@ -0,0 +1,38 @@ +recommendationHistoryService = $recommendationHistoryService; + } + + public function getList() + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $recommendationsHistoryList = $this->recommendationHistoryService->getList($anr); + + return $this->getPreparedJsonResponse([ + 'count' => \count($recommendationsHistoryList), + 'recommendations-history' => $recommendationsHistoryList, + ]); + } +} diff --git a/src/Controller/ApiAnrRecommendationsRisksController.php b/src/Controller/ApiAnrRecommendationsRisksController.php new file mode 100755 index 00000000..0daf1b73 --- /dev/null +++ b/src/Controller/ApiAnrRecommendationsRisksController.php @@ -0,0 +1,83 @@ +getFormattedInputParams($this->getRecommendationRisksInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrRecommendationRiskService->getCount($formattedParams), + 'recommendations-risks' => $this->anrRecommendationRiskService->getList($formattedParams) + ]); + } + + /** + * @param array $data + */ + public function create($data) + { + $this->validatePostParams($this->postRecommendationRiskDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $recommendationRisk = $this->anrRecommendationRiskService->create( + $anr, + $this->postRecommendationRiskDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(['id' => $recommendationRisk->getId()]); + } + + /** + * @param array $data + */ + public function patch($id, $data) + { + $this->validatePostParams($this->patchRecommendationRiskDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrRecommendationRiskService->patch( + $anr, + (int)$id, + $this->patchRecommendationRiskDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrRecommendationRiskService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiAnrRecommendationsRisksValidateController.php b/src/Controller/ApiAnrRecommendationsRisksValidateController.php new file mode 100755 index 00000000..4311af56 --- /dev/null +++ b/src/Controller/ApiAnrRecommendationsRisksValidateController.php @@ -0,0 +1,35 @@ +getRequest()->getAttribute('anr'); + + $this->anrRecommendationRiskService->validateFor($anr, (int)$id, $data); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiAnrRecommendationsSetsController.php b/src/Controller/ApiAnrRecommendationsSetsController.php new file mode 100644 index 00000000..79e4302c --- /dev/null +++ b/src/Controller/ApiAnrRecommendationsSetsController.php @@ -0,0 +1,99 @@ +getRequest()->getAttribute('anr'); + + $recommendationSetsList = $this->anrRecommendationSetService->getList($anr); + + return $this->getPreparedJsonResponse([ + 'count' => \count($recommendationSetsList), + 'recommendations-sets' => $recommendationSetsList, + ]); + } + + /** + * @param string $id + */ + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrRecommendationSetService->getRecommendationSetData($anr, $id)); + } + + /** + * @param array $data + */ + public function create($data) + { + $this->validatePostParams($this->postRecommendationSetDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $recommendationSet = $this->anrRecommendationSetService->create( + $anr, + $this->postRecommendationSetDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(['id' => $recommendationSet->getUuid()]); + } + + /** + * @param string $id + * @param array $data + */ + public function patch($id, $data) + { + $this->validatePostParams($this->postRecommendationSetDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrRecommendationSetService->patch( + $anr, + $id, + $this->postRecommendationSetDataInputValidator->getValidData() + ); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param string $id + */ + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrRecommendationSetService->delete($anr, $id); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiAnrRecordActorsController.php b/src/Controller/ApiAnrRecordActorsController.php index 8e1aedb8..37590f1a 100644 --- a/src/Controller/ApiAnrRecordActorsController.php +++ b/src/Controller/ApiAnrRecordActorsController.php @@ -7,36 +7,29 @@ namespace Monarc\FrontOffice\Controller; -use Laminas\View\Model\JsonModel; +use Monarc\Core\Exception\Exception; +use Monarc\FrontOffice\Service\AnrRecordActorService; -/** - * Api Anr Record Actors Controller - * - * Class ApiAnrRecordActorsController - * @package Monarc\FrontOffice\Controller - */ class ApiAnrRecordActorsController extends ApiAnrAbstractController { protected $name = 'record-actors'; protected $dependencies = ['anr']; + public function __construct(AnrRecordActorService $anrRecordActorService) + { + parent::__construct($anrRecordActorService); + } + public function get($id) { $anrId = (int)$this->params()->fromRoute('anrid'); $entity = $this->getService()->getEntity(['anr' => $anrId, 'id' => $id]); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids are different', 412); - } - if (count($this->dependencies)) { $this->formatDependencies($entity, $this->dependencies); } - return new JsonModel($entity); + return $this->getPreparedJsonResponse($entity); } /** @@ -46,16 +39,13 @@ public function create($data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; $id = $this->getService()->create($data); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(['id' => $id]); } /** @@ -65,13 +55,13 @@ public function update($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; - $service = $this->getService()->update($id, $data); + $this->getService()->update($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } /** diff --git a/src/Controller/ApiAnrRecordActorsControllerFactory.php b/src/Controller/ApiAnrRecordActorsControllerFactory.php deleted file mode 100644 index b10a76ba..00000000 --- a/src/Controller/ApiAnrRecordActorsControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -methodNotAllowed(); } - /** - * @inheritdoc - */ public function update($id, $data) { return $this->methodNotAllowed(); } - /** - * @inheritdoc - */ public function patch($id, $data) { return $this->methodNotAllowed(); } - /** - * @inheritdoc - */ public function delete($id) { return $this->methodNotAllowed(); diff --git a/src/Controller/ApiAnrRecordDataCategoriesControllerFactory.php b/src/Controller/ApiAnrRecordDataCategoriesControllerFactory.php deleted file mode 100644 index e97037a7..00000000 --- a/src/Controller/ApiAnrRecordDataCategoriesControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -getService(); if (!isset($data['record'])) { - throw new \Monarc\Core\Exception\Exception('Record missing', 412); + throw new Exception('Record missing', 412); } - $id = $service->duplicateRecord((int)$data['record'], $data['label']); + $id = $this->anrRecordService->duplicateRecord((int)$data['record'], $data['label']); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(['id' => $id]); } } diff --git a/src/Controller/ApiAnrRecordDuplicateControllerFactory.php b/src/Controller/ApiAnrRecordDuplicateControllerFactory.php deleted file mode 100644 index 461fd41b..00000000 --- a/src/Controller/ApiAnrRecordDuplicateControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; $id = $this->getService()->create($data); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(['id' => $id]); } - /** - * @inheritdoc - */ public function update($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; - $service = $this->getService()->update($id, $data); + $this->getService()->update($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function patch($id, $data) { return $this->methodNotAllowed(); } - /** - * @inheritdoc - */ public function delete($id) { return $this->methodNotAllowed(); diff --git a/src/Controller/ApiAnrRecordInternationalTransfersControllerFactory.php b/src/Controller/ApiAnrRecordInternationalTransfersControllerFactory.php deleted file mode 100644 index 96f0d0e6..00000000 --- a/src/Controller/ApiAnrRecordInternationalTransfersControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $page = $this->params()->fromQuery('page'); $limit = $this->params()->fromQuery('limit'); @@ -35,15 +35,14 @@ public function getList() $service = $this->getService(); $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } + foreach ($entities as $key => $entity) { + $this->formatDependencies($entities[$key], $this->dependencies); } - return new JsonModel(array( + + return $this->getPreparedJsonResponse([ 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - )); + $this->name => $entities, + ]); } public function get($id) @@ -51,64 +50,41 @@ public function get($id) $anrId = (int)$this->params()->fromRoute('anrid'); $entity = $this->getService()->getEntity(['anr' => $anrId, 'id' => $id]); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids are different', 412); - } + $this->formatDependencies($entity, $this->dependencies); - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } - - return new JsonModel($entity); + return $this->getPreparedJsonResponse($entity); } - /** - * @inheritdoc - */ public function create($data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; $id = $this->getService()->createPersonalData($data); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + + return $this->getPreparedJsonResponse(['id' => $id]); } - /** - * @inheritdoc - */ public function update($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; - $service = $this->getService()->updatePersonalData($id, $data); + $this->getService()->updatePersonalData($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function patch($id, $data) { return $this->methodNotAllowed(); } - /** - * @inheritdoc - */ public function delete($id) { return $this->methodNotAllowed(); diff --git a/src/Controller/ApiAnrRecordPersonalDataControllerFactory.php b/src/Controller/ApiAnrRecordPersonalDataControllerFactory.php deleted file mode 100644 index c2bfe91f..00000000 --- a/src/Controller/ApiAnrRecordPersonalDataControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -params()->fromRoute('anrid'); $entity = $this->getService()->getEntity(['anr' => $anrId, 'id' => $id]); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids are different', 412); - } - - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } + $this->formatDependencies($entity, $this->dependencies); - return new JsonModel($entity); + return $this->getPreparedJsonResponse($entity); } - /** - * @inheritdoc - */ public function update($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; $this->getService()->updateProcessor($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function create($data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; $id = $this->getService()->create($data); - return new JsonModel([ - 'status' => 'ok', + return $this->getPreparedJsonResponse([ 'id' => $id, ]); } - /** - * @inheritdoc - */ public function patch($id, $data) { return $this->methodNotAllowed(); } - /** - * @inheritdoc - */ public function delete($id) { return $this->methodNotAllowed(); diff --git a/src/Controller/ApiAnrRecordProcessorsControllerFactory.php b/src/Controller/ApiAnrRecordProcessorsControllerFactory.php deleted file mode 100644 index 3179f57c..00000000 --- a/src/Controller/ApiAnrRecordProcessorsControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; $id = $this->getService()->create($data); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(['id' => $id]); } - /** - * @inheritdoc - */ public function update($id, $data) { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; - $service = $this->getService()->update($id, $data); + $this->getService()->update($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function patch($id, $data) { return $this->methodNotAllowed(); } - /** - * @inheritdoc - */ public function delete($id) { return $this->methodNotAllowed(); diff --git a/src/Controller/ApiAnrRecordRecipientsControllerFactory.php b/src/Controller/ApiAnrRecordRecipientsControllerFactory.php deleted file mode 100644 index e2ba979f..00000000 --- a/src/Controller/ApiAnrRecordRecipientsControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -getService(); $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } + foreach ($entities as $key => $entity) { + $this->formatDependencies($entities[$key], $this->dependencies); } - return new JsonModel(array( + + return $this->getPreparedJsonResponse([ 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - )); + $this->name => $entities, + ]); } public function get($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); $entity = $this->getService()->getEntity(['id' => $id]); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') !== $anrId) { - throw new Exception('Anr ids are different', 412); - } - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } - return new JsonModel($entity); + $this->formatDependencies($entity, $this->dependencies); + + return $this->getPreparedJsonResponse($entity); } - public function formatDependencies(&$entity, $dependencies, $EntityDependency = "", $subField = []) + public function formatDependencies(&$entity, $dependencies, $entityDependency = "", $subField = []) { - foreach($dependencies as $dependency) { + foreach ($dependencies as $dependency) { if (!empty($entity[$dependency])) { - if (is_object($entity[$dependency])) { - if (is_a($entity[$dependency], 'Monarc\Core\Model\Entity\AbstractEntity')) { - if(is_a($entity[$dependency], $EntityDependency)){ //fetch more info + if (\is_object($entity[$dependency])) { + if ($entity[$dependency] instanceof AbstractEntity) { + if ($entity[$dependency] instanceof $entityDependency) { $entity[$dependency] = $entity[$dependency]->getJsonArray(); - if(!empty($subField)){ - foreach ($subField as $key => $value){ - $entity[$dependency][$value] = $entity[$dependency][$value] ? $entity[$dependency][$value]->getJsonArray() : []; - unset($entity[$dependency][$value]['__initializer__']); - unset($entity[$dependency][$value]['__cloner__']); - unset($entity[$dependency][$value]['__isInitialized__']); + if (!empty($subField)) { + foreach ($subField as $value) { + $entity[$dependency][$value] = $entity[$dependency][$value] + ? $entity[$dependency][$value]->getJsonArray() + : []; + unset( + $entity[$dependency][$value]['__initializer__'], + $entity[$dependency][$value]['__cloner__'], + $entity[$dependency][$value]['__isInitialized__'] + ); } } - }else { + } else { $entity[$dependency] = $entity[$dependency]->getJsonArray(); } - unset($entity[$dependency]['__initializer__']); - unset($entity[$dependency]['__cloner__']); - unset($entity[$dependency]['__isInitialized__']); - }else if(get_class($entity[$dependency]) == 'Doctrine\ORM\PersistentCollection') { + } elseif ($entity[$dependency] instanceof PersistentCollection) { $entity[$dependency]->initialize(); - if($entity[$dependency]->count()){ + if ($entity[$dependency]->count()) { $dependencySnapshot = $entity[$dependency]->getSnapshot(); $temp = []; - foreach($dependencySnapshot as $d){ - if(is_a($d, 'Monarc\FrontOffice\Model\Entity\RecordProcessor')) { //fetch more info + foreach ($dependencySnapshot as $d) { + if ($d instanceof RecordProcessor) { $d = $d->getJsonArray(); - if($d['representative']){ + if ($d['representative']) { $d['representative'] = $d['representative']->getJsonArray(); } - if($d['dpo']){ + if ($d['dpo']) { $d['dpo'] = $d['dpo']->getJsonArray(); } $temp[] = $d; - } - else if(is_a($d, 'Monarc\FrontOffice\Model\Entity\RecordPersonalData')) { //fetch more info + } elseif ($d instanceof RecordPersonalData) { $d = $d->getJsonArray(); $d['dataCategories']->initialize(); - if($d['dataCategories']->count()){ + if ($d['dataCategories']->count()) { $dataCategories = $d['dataCategories']->getSnapshot(); $d['dataCategories'] = []; - foreach($dataCategories as $dc){ + foreach ($dataCategories as $dc) { $tempDataCategory = $dc->toArray(); $d['dataCategories'][] = $tempDataCategory; } } - if($d['record']){ + if ($d['record']) { $d['record'] = $d['record']->getJsonArray(); } $temp[] = $d; - } - else if(is_a($d, 'Monarc\Core\Model\Entity\AbstractEntity')){ - $temp[] = $d->getJsonArray(); - }else{ - $temp[] = $d; + } else { + if ($d instanceof AbstractEntity) { + $temp[] = $d->getJsonArray(); + } else { + $temp[] = $d; + } } } $entity[$dependency] = $temp; } - }else if (is_array($entity[$dependency])) { - foreach($entity[$dependency] as $key => $value) { - if (is_a($entity[$dependency][$key], 'Monarc\Core\Model\Entity\AbstractEntity')) { - $entity[$dependency][$key] = $entity[$dependency][$key]->getJsonArray(); - unset($entity[$dependency][$key]['__initializer__']); - unset($entity[$dependency][$key]['__cloner__']); - unset($entity[$dependency][$key]['__isInitialized__']); + } else { + if (\is_array($entity[$dependency])) { + foreach ($entity[$dependency] as $key => $value) { + if ($entity[$dependency][$key] instanceof AbstractEntity) { + $entity[$dependency][$key] = $entity[$dependency][$key]->getJsonArray(); + unset( + $entity[$dependency][$key]['__initializer__'], + $entity[$dependency][$key]['__cloner__'], + $entity[$dependency][$key]['__isInitialized__'] + ); + } } } } @@ -160,26 +169,16 @@ public function update($id, $data) $this->getService()->updateRecord($id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } public function delete($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); - - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - $this->getService()->deleteRecord($id); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function create($data) { $anrId = (int)$this->params()->fromRoute('anrid'); @@ -190,9 +189,6 @@ public function create($data) $id = $this->getService()->create($data); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(['id' => $id]); } } diff --git a/src/Controller/ApiAnrRecordsControllerFactory.php b/src/Controller/ApiAnrRecordsControllerFactory.php deleted file mode 100644 index 911e1f03..00000000 --- a/src/Controller/ApiAnrRecordsControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -getService()->getEntity($data['id']); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - - if ($entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids differents', 412); - } - - $output = $this->getService()->export($data); + $output = $this->anrRecordService->export($data); + $filename = empty($data['filename']) ? $data['id'] : $data['filename']; - if (empty($data['password'])) { - $contentType = 'application/json; charset=utf-8'; - $extension = '.json'; - } else { - $contentType = 'text/plain; charset=utf-8'; - $extension = '.bin'; - } - - $this->getResponse() - ->getHeaders() - ->clearHeaders() - ->addHeaderLine('Content-Type', $contentType) - ->addHeaderLine('Content-Disposition', 'attachment; filename="' . - (empty($data['filename']) ? $data['id'] : $data['filename']) . $extension . '"'); - - $this->getResponse() - ->setContent($output); + return $this->prepareJsonExportResponse($filename, $output, !empty($data['password'])); + } - return $this->getResponse(); - } elseif ($data['export'] == "All") { - if (empty($data['password'])) { - $contentType = 'application/json; charset=utf-8'; - $extension = '.json'; - } else { - $contentType = 'text/plain; charset=utf-8'; - $extension = '.bin'; - } + if ($data['export'] === "All") { $anrId = (int)$this->params()->fromRoute('anrid'); if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); + throw new Exception('Anr id missing', 412); } $data['anr'] = $anrId; - $data['filename'] = "records_list"; - $output = $this->getService()->exportAll($data); - - $this->getResponse() - ->getHeaders() - ->clearHeaders() - ->addHeaderLine('Content-Type', $contentType) - ->addHeaderLine('Content-Disposition', 'attachment; filename="' . - (empty($data['filename']) ? $data['id'] : $data['filename']) . $extension . '"'); - - $this->getResponse() - ->setContent($output); + $output = $this->anrRecordService->exportAll($data); - return $this->getResponse(); - } else { - throw new \Monarc\Core\Exception\Exception('Record to export is required', 412); + return $this->prepareJsonExportResponse('records_list', $output, !empty($data['password'])); } - } - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function getList() - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) - { - return $this->methodNotAllowed(); + throw new Exception('Record to export is required', 412); } } diff --git a/src/Controller/ApiAnrRecordsExportControllerFactory.php b/src/Controller/ApiAnrRecordsExportControllerFactory.php deleted file mode 100644 index e77e4304..00000000 --- a/src/Controller/ApiAnrRecordsExportControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -anrRecordService = $anrRecordService; } public function create($data) @@ -36,8 +35,7 @@ public function create($data) [$ids, $errors] = $this->anrRecordService->importFromFile($anrId, $data); - return new JsonModel([ - 'status' => 'ok', + return $this->getSuccessfulJsonResponse([ 'id' => $ids, 'errors' => $errors, ]); diff --git a/src/Controller/ApiAnrReferentialsController.php b/src/Controller/ApiAnrReferentialsController.php index 76b0e31e..703ecaff 100644 --- a/src/Controller/ApiAnrReferentialsController.php +++ b/src/Controller/ApiAnrReferentialsController.php @@ -1,98 +1,91 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $filterAnd = ['anr' => $anrId]; - - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } + $formatterParams = $this->getFormattedInputParams($this->getReferentialInputFormatter); - return new JsonModel(array( - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - )); + return $this->getPreparedJsonResponse([ + 'referentials' => $this->anrReferentialService->getList($formatterParams), + ]); } + /** + * @param string $id + */ public function get($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $entity = $this->getService()->getEntity(['anr' => $anrId, 'uuid' => $id]); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids diffence', 412); - } + return $this->getPreparedJsonResponse($this->anrReferentialService->getReferentialData($anr, $id)); + } + + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->validatePostParams($this->postReferentialDataInputValidator, $data); - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } - return new JsonModel($entity); + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrReferentialService->create( + $anr, + $this->postReferentialDataInputValidator->getValidData() + )->getUuid(), + ]); } + /** + * @param string $id + * @param array $data + */ public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $newId = ['anr'=> $anrId, 'uuid' => $data['uuid']]; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->validatePostParams($this->postReferentialDataInputValidator, $data); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; + $this->anrReferentialService->update($anr, $id, $this->postReferentialDataInputValidator->getValidData()); - $this->getService()->update($newId, $data); - - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } + /** + * @param string $id + */ public function delete($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $newId = ['anr'=> $anrId, 'uuid' => $id]; - - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - $this->getService()->delete($newId); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrReferentialService->delete($anr, $id); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrReferentialsControllerFactory.php b/src/Controller/ApiAnrReferentialsControllerFactory.php deleted file mode 100644 index 8916ce48..00000000 --- a/src/Controller/ApiAnrReferentialsControllerFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $instanceRiskOwners = $this->instanceRiskOwnerService->getList($anrId, $this->prepareParams()); + $instanceRiskOwners = $this->instanceRiskOwnerService->getList($anr, $this->prepareParams()); - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'instanceRiskOwners' => $instanceRiskOwners, 'count' => \count($instanceRiskOwners), ]); diff --git a/src/Controller/ApiAnrRisksController.php b/src/Controller/ApiAnrRisksController.php index 1a61dde1..4fb46fd3 100755 --- a/src/Controller/ApiAnrRisksController.php +++ b/src/Controller/ApiAnrRisksController.php @@ -1,50 +1,52 @@ -anrInstanceRiskService = $anrInstanceRiskService; } + /** + * Fetch instance risks by instance ID or for the whole analysis if id is null. + * + * @param int|string|null $id Instance id. + */ public function get($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); $params = $this->prepareParams(); + $id = $id === null ? null : (int)$id; if ($this->params()->fromQuery('csv', false)) { - /** @var Response $response */ - $response = $this->getResponse(); - $response->getHeaders()->addHeaderLine('Content-Type', 'text/csv; charset=utf-8'); - $response->setContent($this->anrInstanceRiskService->getInstanceRisksInCsv($anrId, $id, $params)); - - return $response; + return $this->prepareCsvExportResponse( + $this->anrInstanceRiskService->getInstanceRisksInCsv($anr, $id, $params) + ); } - $risks = $this->anrInstanceRiskService->getInstanceRisks($anrId, $id, $params); + $risks = $this->anrInstanceRiskService->getInstanceRisks($anr, $id, $params); - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'count' => \count($risks), 'risks' => $params['limit'] > 0 ? \array_slice($risks, ($params['page'] - 1) * $params['limit'], $params['limit']) @@ -52,42 +54,14 @@ public function get($id) ]); } + /** + * Fetch all the instance risks of the analysis. + */ public function getList() { return $this->get(null); } - public function create($data) - { - $params = [ - 'anr' => (int)$this->params()->fromRoute('anrid'), - 'instance' => $data['instance'], - 'specific' => $data['specific'], - 'threat' => [ - 'uuid' => $data['threat'], - 'anr' => $data['anrId'], - ], - 'vulnerability' => [ - 'uuid' => $data['vulnerability'], - 'anr' => $data['anrId'], - ], - ]; - - $id = $this->anrInstanceRiskService->createInstanceRisk($params); - - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); - } - - public function delete($id) - { - $this->anrInstanceRiskService->deleteInstanceRisk((int)$id, (int)$this->params()->fromRoute('anrid')); - - return new JsonModel(['status' => 'ok']); - } - protected function prepareParams(): array { $params = $this->params(); @@ -98,8 +72,8 @@ protected function prepareParams(): array 'order' => $params->fromQuery('order', 'maxRisk'), 'order_direction' => $params->fromQuery('order_direction', 'desc'), 'thresholds' => $params->fromQuery('thresholds'), - 'page' => $params->fromQuery('page', 1), - 'limit' => $params->fromQuery('limit', 50), + 'page' => (int)$params->fromQuery('page', 1), + 'limit' => (int)$params->fromQuery('limit', 50), 'amvs' => $params->fromQuery('amvs') ]; } diff --git a/src/Controller/ApiAnrRisksOpController.php b/src/Controller/ApiAnrRisksOpController.php index 5d908a52..52f721bb 100755 --- a/src/Controller/ApiAnrRisksOpController.php +++ b/src/Controller/ApiAnrRisksOpController.php @@ -1,57 +1,51 @@ -anrInstanceRiskOpService = $anrInstanceRiskOpService; } /** - * @param int $id Instance ID. + * Fetch operational instance risks by instance ID or for the whole analysis if id is null. * - * @return Response|JsonModel + * @param int|string|null $id Instance id. */ public function get($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); $params = $this->getFilterParams(); + $id = $id === null ? null : (int)$id; if ($this->params()->fromQuery('csv', false)) { - /** @var Response $response */ - $response = $this->getResponse(); - $response->getHeaders()->addHeaderLine('Content-Type', 'text/csv; charset=utf-8'); - $response->setContent( - $this->anrInstanceRiskOpService->getOperationalRisksInCsv($anrId, $id, $params) + return $this->prepareCsvExportResponse( + $this->anrInstanceRiskOpService->getOperationalRisksInCsv($anr, $id, $params) ); - - return $response; } - $risks = $this->anrInstanceRiskOpService->getOperationalRisks($anrId, $id, $params); + $risks = $this->anrInstanceRiskOpService->getOperationalRisks($anr, $id, $params); - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'count' => \count($risks), 'oprisks' => $params['limit'] > 0 ? \array_slice($risks, ($params['page'] - 1) * $params['limit'], $params['limit']) @@ -61,51 +55,7 @@ public function get($id) public function getList() { - $anrId = (int)$this->params()->fromRoute('anrid'); - $params = $this->getFilterParams(); - - if ($this->params()->fromQuery('csv', false)) { - /** @var Response $response */ - $response = $this->getResponse(); - $response->getHeaders()->addHeaderLine('Content-Type', 'text/csv; charset=utf-8'); - $response->setContent( - $this->anrInstanceRiskOpService->getOperationalRisksInCsv($anrId, null, $params) - ); - - return $response; - } - - $risks = $this->anrInstanceRiskOpService->getOperationalRisks($anrId, null, $params); - - return new JsonModel([ - 'count' => \count($risks), - 'oprisks' => $params['limit'] > 0 - ? \array_slice($risks, ($params['page'] - 1) * $params['limit'], $params['limit']) - : $risks, - ]); - } - - public function create($data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - - return new JsonModel([ - 'status' => 'ok', - 'id' => $this->anrInstanceRiskOpService->createSpecificRiskOp($data), - ]); - } - - public function delete($id) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - - $this->anrInstanceRiskOpService->deleteFromAnr($id, $anrId); - - return new JsonModel(['status' => 'ok']); + return $this->get(null); } protected function getFilterParams(): array @@ -118,8 +68,8 @@ protected function getFilterParams(): array 'order' => $params->fromQuery('order', 'maxRisk'), 'order_direction' => $params->fromQuery('order_direction', 'desc'), 'thresholds' => $params->fromQuery('thresholds'), - 'page' => $params->fromQuery('page', 1), - 'limit' => $params->fromQuery('limit', 50), + 'page' => (int)$params->fromQuery('page', 1), + 'limit' => (int)$params->fromQuery('limit', 50), 'rolfRisks' => $params->fromQuery('rolfRisks') ]; } diff --git a/src/Controller/ApiAnrRolfRisksController.php b/src/Controller/ApiAnrRolfRisksController.php index aa10fbd6..a16bfab7 100755 --- a/src/Controller/ApiAnrRolfRisksController.php +++ b/src/Controller/ApiAnrRolfRisksController.php @@ -1,106 +1,114 @@ -getService()->getEntity($id); + $formattedParams = $this->getFormattedInputParams($this->rolfRisksInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrRolfRiskService->getCount($formattedParams), + 'risks' => $this->anrRolfRiskService->getList($formattedParams), + ]); + } - $this->formatDependencies($entity, $this->dependencies, Measure::class, ['referential']); + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel($entity); + return $this->getPreparedJsonResponse($this->anrRolfRiskService->getRolfRiskData($anr, (int)$id)); } /** - * @inheritdoc + * @param array $data */ - public function getList() + public function create($data) { - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $tag = $this->params()->fromQuery('tag'); - $anr = $this->params()->fromRoute("anrid"); - - /** @var AnrRolfRiskService $service */ - $service = $this->getService(); - - $rolfRisks = $service->getListSpecific($page, $limit, $order, $filter, $tag, $anr); - foreach ($rolfRisks as $key => $rolfRisk) { - $this->formatDependencies($rolfRisks[$key], $this->dependencies, Measure::class, ['referential']); - - $rolfRisk['tags']->initialize(); - $rolfTags = $rolfRisk['tags']->getSnapshot(); - $rolfRisks[$key]['tags'] = []; - foreach ($rolfTags as $rolfTag) { - $rolfRisks[$key]['tags'][] = $rolfTag->getJsonArray(); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $isBatchData = $this->isBatchData($data); + $this->validatePostParams($this->postRolfRiskDataInputValidator, $data, $isBatchData); + + if ($this->isBatchData($data)) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrRolfRiskService + ->createList($anr, $this->postRolfRiskDataInputValidator->getValidDataSets()), + ]); } - return new JsonModel([ - 'count' => $service->getFilteredSpecificCount($page, $limit, $order, $filter, $tag, $anr), - $this->name => $rolfRisks, + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrRolfRiskService + ->create($anr, $this->postRolfRiskDataInputValidator->getValidData())->getId(), ]); } + /** + * @param array $data + */ public function update($id, $data) { - if (!empty($data['measures'])) { - $data['measures'] = $this->addAnrId($data['measures']); - } - - return parent::update($id, $data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->validatePostParams( + $this->postRolfRiskDataInputValidator + ->setIncludeFilter(['anr' => $anr]) + ->setExcludeFilter(['id' => (int)$id]), + $data + ); + + $this->anrRolfRiskService->update($anr, (int)$id, $this->postRolfRiskDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); } - public function patch($id, $data) + public function patchList($data) { - if (!empty($data['measures'])) { - $data['measures'] = $this->addAnrId($data['measures']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrRolfRiskService->linkMeasuresToRisks($anr, $data['fromReferential'], $data['toReferential']); - return parent::patch($id, $data); + return $this->getSuccessfulJsonResponse(); } - - public function patchList($data) + public function delete($id) { - $service = $this->getService(); - $data['toReferential'] = $this->addAnrId($data['toReferential']); - $service->createLinkedRisks($data['fromReferential'], $data['toReferential']); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrRolfRiskService->delete($anr, (int)$id); - return new JsonModel([ - 'status' => 'ok', - ]); + return $this->getSuccessfulJsonResponse(); } - public function create($data) + public function deleteList($data) { - if (!empty($data['measures'])) { - $data['measures'] = $this->addAnrId($data['measures']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrRolfRiskService->deleteList($anr, $data); - return parent::create($data); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrRolfRisksControllerFactory.php b/src/Controller/ApiAnrRolfRisksControllerFactory.php deleted file mode 100755 index 2965d357..00000000 --- a/src/Controller/ApiAnrRolfRisksControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getFormattedInputParams($this->getRolfTagsInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrRolfTagService->getCount($formattedParams), + 'tags' => $this->anrRolfTagService->getList($formattedParams), + ]); + } + + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrRolfTagService->getRolfTagData($anr, (int)$id)); + } + + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $isBatchData = $this->isBatchData($data); + $this->validatePostParams($this->postRolfTagDataInputValidator, $data, $isBatchData); + + if ($this->isBatchData($data)) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrRolfTagService + ->createList($anr, $this->postRolfTagDataInputValidator->getValidDataSets()), + ]); + } + + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrRolfTagService->create( + $anr, + $this->postRolfTagDataInputValidator->getValidData() + )->getId(), + ]); + } + + /** + * @param array $data + */ + public function update($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->validatePostParams( + $this->postRolfTagDataInputValidator + ->setIncludeFilter(['anr' => $anr]) + ->setExcludeFilter(['id' => (int)$id]), + $data + ); + + $this->anrRolfTagService->update($anr, (int)$id, $this->postRolfTagDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrRolfTagService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); + } + + public function deleteList($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrRolfTagService->deleteList($anr, $data); + + return $this->getSuccessfulJsonResponse(); + } } diff --git a/src/Controller/ApiAnrRolfTagsControllerFactory.php b/src/Controller/ApiAnrRolfTagsControllerFactory.php deleted file mode 100755 index cdc66acd..00000000 --- a/src/Controller/ApiAnrRolfTagsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); + use ControllerRequestResponseHandlerTrait; - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $filterAnd = ['anr' => $anrId]; - - $scaleId = (int)$this->params()->fromRoute('scaleid'); - if (empty($scaleId)) { - throw new \Monarc\Core\Exception\Exception('Scale id missing', 412); - } - $filterAnd['scale'] = $scaleId; - - $service = $this->getService(); - - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - ]); + public function __construct( + private AnrScaleCommentService $anrScaleCommentService, + private GetScaleCommentsInputFormatter $getScaleCommentsInputFormatter + ) { } - /** - * @inheritdoc - */ - public function get($id) + public function getList() { - $entity = $this->getService()->getEntity($id); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - if (!$entity['anr'] || $entity['anr']->get('id') != $anrId) { - throw new \Monarc\Core\Exception\Exception('Anr ids diffence', 412); - } - - $scaleId = (int)$this->params()->fromRoute('scaleid'); - if (empty($scaleId)) { - throw new \Monarc\Core\Exception\Exception('Scale id missing', 412); - } - if (!$entity['scale'] || $entity['scale']->get('id') != $scaleId) { - throw new \Monarc\Core\Exception\Exception('Scale ids diffence', 412); - } + $formattedParams = $this->getFormattedInputParams($this->getScaleCommentsInputFormatter); + $formattedParams->setFilterValueFor('scale', (int)$this->params()->fromRoute('scaleid')); - if (count($this->dependencies)) { - $this->formatDependencies($entity, $this->dependencies); - } + $comments = $this->anrScaleCommentService->getList($formattedParams); - return new JsonModel($entity); + return $this->getPreparedJsonResponse([ + 'count' => \count($comments), + 'comments' => $comments, + ]); } /** - * @inheritdoc + * @param array $data */ public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - $scaleId = (int)$this->params()->fromRoute('scaleid'); - if (empty($scaleId)) { - throw new \Monarc\Core\Exception\Exception('Scale id missing', 412); - } - $data['scale'] = $scaleId; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $id = $this->getService()->create($data); + $scaleComment = $this->anrScaleCommentService->create($anr, $data); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, - ]); + return $this->getSuccessfulJsonResponse(['id' => $scaleComment->getId()]); } /** - * @inheritdoc + * @param array $data */ public function update($id, $data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - $scaleId = (int)$this->params()->fromRoute('scaleid'); - if (empty($scaleId)) { - throw new \Monarc\Core\Exception\Exception('Scale id missing', 412); - } - $data['scale'] = $scaleId; - - $this->getService()->update($id, $data); - - return new JsonModel(['status' => 'ok']); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; - $scaleId = (int)$this->params()->fromRoute('scaleid'); - if (empty($scaleId)) { - throw new \Monarc\Core\Exception\Exception('Scale id missing', 412); - } - $data['scale'] = $scaleId; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $this->getService()->patch($id, $data); + $scaleComment = $this->anrScaleCommentService->update($anr, (int)$id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(['id' => $scaleComment->getId()]); } } diff --git a/src/Controller/ApiAnrScalesCommentsControllerFactory.php b/src/Controller/ApiAnrScalesCommentsControllerFactory.php deleted file mode 100755 index 0df2a692..00000000 --- a/src/Controller/ApiAnrScalesCommentsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $filterAnd = ['anr' => $anrId]; - - $service = $this->getService(); - - list($entities, $canChange) = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities, - 'canChange' => $canChange, + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $scalesData = $this->anrScaleService->getList($anr); + + return $this->getPreparedJsonResponse([ + 'count' => \count($scalesData), + 'scales' => $scalesData, + 'canChange' => !$this->anrScaleService->areScalesNotEditable($anr), ]); } + + /** + * @param array $data + */ + public function update($id, $data) + { + $this->validatePostParams($this->updateScalesDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrScaleService->update($anr, (int)$id, $this->updateScalesDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); + } } diff --git a/src/Controller/ApiAnrScalesControllerFactory.php b/src/Controller/ApiAnrScalesControllerFactory.php deleted file mode 100755 index 5838a71a..00000000 --- a/src/Controller/ApiAnrScalesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $data['anr'] = $anrId; + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $id = $this->getService()->create($data); + $scaleImpactTypesList = $this->scaleImpactTypeService->getList($anr); - return new JsonModel([ - 'status' => 'ok', - 'id' => $id, + return $this->getPreparedJsonResponse([ + 'count' => \count($scaleImpactTypesList), + 'types' => $scaleImpactTypesList, ]); } + + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $scaleType = $this->scaleImpactTypeService->create($anr, $data); + + return $this->getSuccessfulJsonResponse(['id' => $scaleType->getId()]); + } + + public function patch($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->scaleImpactTypeService->patch($anr, (int)$id, $data); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->scaleImpactTypeService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); + } } diff --git a/src/Controller/ApiAnrScalesTypesControllerFactory.php b/src/Controller/ApiAnrScalesTypesControllerFactory.php deleted file mode 100755 index 9194d5e5..00000000 --- a/src/Controller/ApiAnrScalesTypesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getFormattedInputParams($this->getThemesInputFormatter); + + return $this->getPreparedJsonResponse([ + 'themes' => $this->anrThemeService->getList($formatterParams), + ]); + } + + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrThemeService->getThemeData($anr, (int)$id)); + } + + public function create($data) + { + $this->validatePostParams($this->postThemeDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $theme = $this->anrThemeService->create($anr, $data); + + return $this->getSuccessfulJsonResponse(['id' => $theme->getId()]); + } + + + public function update($id, $data) + { + $this->validatePostParams($this->postThemeDataInputValidator, $data); + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrThemeService->update($anr, (int)$id, $data); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->anrThemeService->delete($anr, (int)$id); + + return $this->getSuccessfulJsonResponse(); + } } diff --git a/src/Controller/ApiAnrThemesControllerFactory.php b/src/Controller/ApiAnrThemesControllerFactory.php deleted file mode 100755 index 10f74845..00000000 --- a/src/Controller/ApiAnrThemesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getFormattedInputParams($this->getThreatsInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrThreatService->getCount($formattedParams), + 'threats' => $this->anrThreatService->getList($formattedParams), + ]); + } + + /** + * @param string $id + */ + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrThreatService->getThreatData($anr, $id)); + } + + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $isBatchData = $this->isBatchData($data); + $this->validatePostParams( + $this->postThreatDataInputValidator->setIncludeFilter(['anr' => $anr]), + $data, + $isBatchData + ); + + if ($isBatchData) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrThreatService->createList( + $anr, + $this->postThreatDataInputValidator->getValidDataSets() + ), + ]); + } + + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrThreatService->create( + $anr, + $this->postThreatDataInputValidator->getValidData() + )->getUuid(), + ]); + } + + /** + * @param string $id + * @param array $data + */ + public function update($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->validatePostParams( + $this->postThreatDataInputValidator->setIncludeFilter(['anr' => $anr])->setExcludeFilter(['uuid' => $id]), + $data + ); + + $this->anrThreatService->update($anr, $id, $this->postThreatDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param string $id + * @param array $data + */ + public function patch($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrThreatService->patch($anr, $id, $data); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param string $id + */ + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrThreatService->delete($anr, $id); + + return $this->getSuccessfulJsonResponse(); + } + + /** + * @param array $data + */ + public function deleteList($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrThreatService->deleteList($anr, $data); - protected $dependencies = ['anr', 'theme']; + return $this->getSuccessfulJsonResponse(); + } } diff --git a/src/Controller/ApiAnrThreatsControllerFactory.php b/src/Controller/ApiAnrThreatsControllerFactory.php deleted file mode 100755 index 312866b4..00000000 --- a/src/Controller/ApiAnrThreatsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } + use ControllerRequestResponseHandlerTrait; - /** @var AnrRecommandationRiskService $service */ - $service = $this->getService(); - $entities = $service->getTreatmentPlan($anrId); - - return new JsonModel([ - 'recommandations-risks' => $entities - ]); + public function __construct(private AnrRecommendationRiskService $anrRecommendationRiskService) + { } - /** - * @inheritdoc - */ - public function get($id) + public function getList() { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** @var AnrRecommandationRiskService $service */ - $service = $this->getService(); - $entities = $service->getTreatmentPlan($anrId, $id); - if (empty($entities)) { - throw new Exception('Entity does not exist', 412); - } - - return new JsonModel($entities[0]); + return $this->getPreparedJsonResponse([ + 'recommendations-risks' => $this->anrRecommendationRiskService->getTreatmentPlan($anr) + ]); } - /** - * @inheritdoc - */ public function deleteList($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - /** @var AnrRecommandationRiskService $service */ - $service = $this->getService(); - $service->resetRecommendationsPositionsToDefault($anrId); - - return new JsonModel(['status' => 'ok']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } + $this->anrRecommendationRiskService->resetRecommendationsPositionsToDefault($anr); - /** - * @inheritdoc - */ - public function patch($token, $data) - { - return $this->methodNotAllowed(); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiAnrTreatmentPlanControllerFactory.php b/src/Controller/ApiAnrTreatmentPlanControllerFactory.php deleted file mode 100755 index 4e495ee5..00000000 --- a/src/Controller/ApiAnrTreatmentPlanControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getFormattedInputParams($this->getVulnerabilitiesInputFormatter); + + return $this->getPreparedJsonResponse([ + 'count' => $this->anrVulnerabilityService->getCount($formattedInput), + 'vulnerabilities' => $this->anrVulnerabilityService->getList($formattedInput), + ]); + } + + /** + * @param string $id + */ + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->anrVulnerabilityService->getVulnerabilityData($anr, $id)); + } + + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $isBatchData = $this->isBatchData($data); + $this->validatePostParams( + $this->postVulnerabilityDataInputValidator->setIncludeFilter(['anr' => $anr]), + $data, + $isBatchData + ); + + if ($isBatchData) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrVulnerabilityService->createList( + $anr, + $this->postVulnerabilityDataInputValidator->getValidDataSets() + ), + ]); + } + + return $this->getSuccessfulJsonResponse([ + 'id' => $this->anrVulnerabilityService->create( + $anr, + $this->postVulnerabilityDataInputValidator->getValidData() + )->getUuid(), + ]); + } + + /** + * @param string $id + * @param array $data + */ + public function update($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->validatePostParams( + $this->postVulnerabilityDataInputValidator + ->setIncludeFilter(['anr' => $anr]) + ->setExcludeFilter(['uuid' => $id]), + $data + ); + + $this->anrVulnerabilityService->update($anr, $id, $this->postVulnerabilityDataInputValidator->getValidData()); + + return $this->getPreparedJsonResponse(['status' => 'ok']); + } + + public function patch($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrVulnerabilityService->patch($anr, $id, $data); + + return $this->getPreparedJsonResponse(['status' => 'ok']); + } + + /** + * @param string $id + */ + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrVulnerabilityService->delete($anr, $id); + + return $this->getPreparedJsonResponse(['status' => 'ok']); + } + + public function deleteList($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->anrVulnerabilityService->deleteList($anr, $data); + + return $this->getPreparedJsonResponse(['status' => 'ok']); + } } diff --git a/src/Controller/ApiAnrVulnerabilitiesControllerFactory.php b/src/Controller/ApiAnrVulnerabilitiesControllerFactory.php deleted file mode 100755 index 3fcea82a..00000000 --- a/src/Controller/ApiAnrVulnerabilitiesControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -clientService = $clientService; } public function getList() { - return new JsonModel($this->clientService->getAll()); + return $this->getPreparedJsonResponse($this->clientService->getAll()); + } + + public function create($data) + { + $this->clientService->create($data); + + return $this->getSuccessfulJsonResponse(); } public function patch($id, $data) { $this->clientService->patch((int)$id, $data); - return new JsonModel(array('status' => 'ok')); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiConfigController.php b/src/Controller/ApiConfigController.php index ac1006f4..065ae4b1 100755 --- a/src/Controller/ApiConfigController.php +++ b/src/Controller/ApiConfigController.php @@ -1,7 +1,7 @@ configService = $configService; } public function getList() @@ -28,8 +25,7 @@ public function getList() $this->configService->getCheckVersion(), $this->configService->getAppCheckingURL(), $this->configService->getMospApiUrl(), - $this->configService->getTerms(), - $this->configService->getConfigOption('import', []) + $this->configService->getTerms() )); } } diff --git a/src/Controller/ApiCoreReferentialsController.php b/src/Controller/ApiCoreReferentialsController.php new file mode 100644 index 00000000..3db0f2f8 --- /dev/null +++ b/src/Controller/ApiCoreReferentialsController.php @@ -0,0 +1,40 @@ +referentialService->getList( + $this->getFormattedInputParams($this->getReferentialInputFormatter) + ); + + return new JsonModel([ + 'count' => \count($frameworks), + 'referentials' => $frameworks, + ]); + } +} diff --git a/src/Controller/ApiDashboardAnrCartoRisksController.php b/src/Controller/ApiDashboardAnrCartoRisksController.php index 4d5083a2..a8d2c352 100644 --- a/src/Controller/ApiDashboardAnrCartoRisksController.php +++ b/src/Controller/ApiDashboardAnrCartoRisksController.php @@ -1,110 +1,49 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } - $type = $this->params()->fromRoute('type', 'all'); // real / targeted / all - switch ($type) { - case 'real': - return new JsonModel([ - 'status' => 'ok', - $this->name => [ - 'real' => $this->getService()->getCartoReal($anrId), - ] - ]); - break; - case 'targeted': - return new JsonModel([ - 'status' => 'ok', - $this->name => [ - 'targeted' => $this->getService()->getCartoTargeted($anrId), - ] - ]); - break; - default: - case 'all': - return new JsonModel([ - 'status' => 'ok', - $this->name => [ - 'real' => $this->getService()->getCartoReal($anrId), - 'targeted' => $this->getService()->getCartoTargeted($anrId), - ] - ]); - break; - } - } - - /** - * @inheritdoc - */ - public function get($id) - { - $this->methodNotAllowed(); - } + use ControllerRequestResponseHandlerTrait; - /** - * @inheritdoc - */ - public function create($data) + public function __construct(private AnrCartoRiskService $anrCartoRiskService) { - $this->methodNotAllowed(); } - /** - * @inheritdoc - */ - public function delete($id) - { - $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function deleteList($data) + public function getList() { - $this->methodNotAllowed(); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - /** - * @inheritdoc - */ - public function update($id, $data) - { - $this->methodNotAllowed(); - } + $type = $this->params()->fromRoute('type', 'all'); // real / targeted / all - /** - * @inheritdoc - */ - public function patch($id, $data) - { - $this->methodNotAllowed(); + return match ($type) { + 'real' => $this->getSuccessfulJsonResponse([ + 'carto' => [ + 'real' => $this->anrCartoRiskService->getCartoReal($anr), + ] + ]), + 'targeted' => $this->getSuccessfulJsonResponse([ + 'carto' => [ + 'targeted' => $this->anrCartoRiskService->getCartoTargeted($anr), + ] + ]), + default => $this->getSuccessfulJsonResponse([ + 'carto' => [ + 'real' => $this->anrCartoRiskService->getCartoReal($anr), + 'targeted' => $this->anrCartoRiskService->getCartoTargeted($anr), + ] + ]), + }; } } diff --git a/src/Controller/ApiDashboardAnrCartoRisksControllerFactory.php b/src/Controller/ApiDashboardAnrCartoRisksControllerFactory.php deleted file mode 100644 index 326e49f8..00000000 --- a/src/Controller/ApiDashboardAnrCartoRisksControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -anrInstanceRiskService = $anrInstanceRiskService; } public function get($id) { - $anrId = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); $params = $this->getParsedParams(); - $instanceRisks = $this->anrInstanceRiskService->getInstanceRisks($anrId, $id, $params); + $id = $id === null ? null : (int)$id; + $instanceRisks = $this->anrInstanceRiskService->getInstanceRisks($anr, $id, $params); - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'count' => \count($instanceRisks), 'risks' => $params['limit'] > 0 ? \array_slice($instanceRisks, ($params['page'] - 1) * $params['limit'], $params['limit']) @@ -49,8 +51,8 @@ private function getParsedParams(): array 'order' => $this->params()->fromQuery('order', 'maxRisk'), 'order_direction' => $this->params()->fromQuery('order_direction', 'desc'), 'thresholds' => $this->params()->fromQuery('thresholds'), - 'page' => $this->params()->fromQuery('page', 1), - 'limit' => $this->params()->fromQuery('limit', 50) + 'page' => (int)$this->params()->fromQuery('page', 1), + 'limit' => (int)$this->params()->fromQuery('limit', 50) ]; } } diff --git a/src/Controller/ApiDeliveriesModelsController.php b/src/Controller/ApiDeliveriesModelsController.php index 7ae3a941..0e3a09a7 100644 --- a/src/Controller/ApiDeliveriesModelsController.php +++ b/src/Controller/ApiDeliveriesModelsController.php @@ -4,43 +4,41 @@ * @copyright Copyright (c) 2016-2020 SMILE GIE Securitymadein.lu - Licensed under GNU Affero GPL v3 * @license MONARC is licensed under GNU Affero General Public License version 3 */ + namespace Monarc\FrontOffice\Controller; use Monarc\Core\Controller\AbstractController; -use Laminas\View\Model\JsonModel; +use Monarc\Core\Controller\Handler\ControllerRequestResponseHandlerTrait; +use Monarc\Core\Exception\Exception; +use Monarc\Core\Service\DeliveriesModelsService; +use Monarc\FrontOffice\Export\Controller\Traits\ExportResponseControllerTrait; -/** - * Api Doc Models Controller - * - * Class ApiDeliveriesModelsController - * @package Monarc\FrontOffice\Controller - */ class ApiDeliveriesModelsController extends AbstractController { - protected $name = "deliveriesmodels"; + use ControllerRequestResponseHandlerTrait; + use ExportResponseControllerTrait; + + public function __construct(DeliveriesModelsService $deliveriesModelsService) + { + parent::__construct($deliveriesModelsService); + } - /** - * @inheritdoc - */ public function create($data) { $service = $this->getService(); $file = $this->request->getFiles()->toArray(); for ($i = 1; $i <= 4; ++$i) { - unset($data['path'.$i]); + unset($data['path' . $i]); if (!empty($file['file'][$i])) { - $file['file'][$i]['name'] = $data['category'] . ".docx"; + $file['file'][$i]['name'] = $data['category'] . ".docx"; $data['path' . $i] = $file['file'][$i]; } } $service->create($data); - return new JsonModel(array('status' => 'ok')); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function getList() { $page = $this->params()->fromQuery('page'); @@ -51,106 +49,80 @@ public function getList() $service = $this->getService(); $entities = $service->getList($page, $limit, $order, $filter); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - $pathModel = getenv('APP_CONF_DIR') ? getenv('APP_CONF_DIR') : ''; - foreach($entities as $k => $v){ - for($i=1;$i<=4;$i++){ - $entities[$k]['filename'.$i] = ''; - if(!empty($entities[$k]['path'.$i])){ + $pathModel = getenv('APP_CONF_DIR') ?: ''; + foreach ($entities as $k => $v) { + for ($i = 1; $i <= 4; $i++) { + $entities[$k]['filename' . $i] = ''; + if (!empty($entities[$k]['path' . $i])) { // $name = explode('_',pathinfo($entities[$k]['path'.$i],PATHINFO_BASENAME)); // unset($name[0]); - $currentPath = $pathModel . $entities[$k]['path'.$i]; + $currentPath = $pathModel . $entities[$k]['path' . $i]; if (!file_exists($currentPath)) { - $entities[$k]['filename'.$i] = ''; - $entities[$k]['path'.$i] = ''; + $entities[$k]['filename' . $i] = ''; + $entities[$k]['path' . $i] = ''; } else { - $entities[$k]['filename'.$i] = pathinfo($entities[$k]['path'.$i],PATHINFO_BASENAME); - $entities[$k]['path'.$i] = './api/deliveriesmodels/'.$v['id'].'?lang='.$i; + $entities[$k]['filename' . $i] = pathinfo($entities[$k]['path' . $i], PATHINFO_BASENAME); + $entities[$k]['path' . $i] = './api/deliveriesmodels/' . $v['id'] . '?lang=' . $i; } } } } - return new JsonModel(array( - 'count' => count($entities), - $this->name => $entities - )); + return $this->getPreparedJsonResponse([ + 'count' => \count($entities), + 'deliveriesmodels' => $entities, + ]); } - /** - * @inheritdoc - */ public function get($id) { $entity = $this->getService()->getEntity($id); - if(!empty($entity)){ - $lang = $this->params()->fromQuery('lang',1); - $pathModel = getenv('APP_CONF_DIR') ? getenv('APP_CONF_DIR') : ''; - $currentPath = $pathModel . $entity['path'.$lang]; - if(isset($entity['path'.$lang]) && file_exists($currentPath)){ + if (!empty($entity)) { + $lang = $this->params()->fromQuery('lang', 1); + $pathModel = getenv('APP_CONF_DIR') ?: ''; + $currentPath = $pathModel . $entity['path' . $lang]; + if (isset($entity['path' . $lang]) && file_exists($currentPath)) { $name = pathinfo($currentPath)['basename']; $fileContents = file_get_contents($currentPath); - if($fileContents !== false){ - $response = $this->getResponse(); - $response->setContent($fileContents); - - $headers = $response->getHeaders(); - $headers->clearHeaders() - ->addHeaderLine('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') - ->addHeaderLine('Content-Disposition', 'attachment; filename="' . utf8_decode($name) . '"') - ->addHeaderLine('Content-Length', strlen($fileContents)); - - return $this->response; - }else{ - throw new \Monarc\Core\Exception\Exception('Document template not found'); + if ($fileContents !== false) { + return $this->prepareWordExportResponse($name, $fileContents); } - }else{ - throw new \Monarc\Core\Exception\Exception('Document template not found'); } - } else { - throw new \Monarc\Core\Exception\Exception('Document template not found'); } + + throw new Exception('Document template not found'); } - /** - * @inheritdoc - */ public function update($id, $data) { - $service = $this->getService(); $file = $this->request->getFiles()->toArray(); for ($i = 1; $i <= 4; ++$i) { - unset($data['path'.$i]); + unset($data['path' . $i]); if (!empty($file['file'][$i])) { $data['path' . $i] = $file['file'][$i]; } } - $service->update($id,$data); - return new JsonModel(array('status' => 'ok')); + $service->update($id, $data); + + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function patch($id, $data) { $service = $this->getService(); $file = $this->request->getFiles()->toArray(); for ($i = 1; $i <= 4; ++$i) { - unset($data['path'.$i]); + unset($data['path' . $i]); if (!empty($file['file'][$i])) { $data['path' . $i] = $file['file'][$i]; } } - $service->patch($id,$data); - return new JsonModel(array('status' => 'ok')); + $service->patch($id, $data); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiDeliveriesModelsControllerFactory.php b/src/Controller/ApiDeliveriesModelsControllerFactory.php deleted file mode 100644 index ebb2bc00..00000000 --- a/src/Controller/ApiDeliveriesModelsControllerFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -anrService = $anrService; + } /** - * @inheritdoc + * @param array $data */ public function create($data) { - /** @var AnrService $service */ - $service = $this->getService(); - - if (!isset($data['anr'])) { - throw new \Monarc\Core\Exception\Exception('Anr missing', 412); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $newAnr = $service->duplicateAnr((int)$data['anr'], MonarcObject::SOURCE_CLIENT, null, $data); + $newAnr = $this->anrService->duplicateAnr($anr, $data); - return new JsonModel([ - 'status' => 'ok', + return $this->getSuccessfulJsonResponse([ 'id' => $newAnr->getId(), ]); } diff --git a/src/Controller/ApiDuplicateAnrControllerFactory.php b/src/Controller/ApiDuplicateAnrControllerFactory.php deleted file mode 100755 index 6e721627..00000000 --- a/src/Controller/ApiDuplicateAnrControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); @@ -32,24 +27,16 @@ public function getList() $order = $this->params()->fromQuery('order'); $filter = $this->params()->fromQuery('filter'); $guide = $this->params()->fromQuery('guide'); - if (!is_null($guide)) { + $filterAnd = []; + if (!\is_null($guide)) { $filterAnd = ['guide' => (int)$guide]; - } else { - $filterAnd = []; } $service = $this->getService(); - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities + 'guides-items' => $service->getList($page, $limit, $order, $filter, $filterAnd), ]); } } diff --git a/src/Controller/ApiGuidesItemsControllerFactory.php b/src/Controller/ApiGuidesItemsControllerFactory.php deleted file mode 100755 index a7e34522..00000000 --- a/src/Controller/ApiGuidesItemsControllerFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -instanceMetadataService = $instanceMetadataService; } - public function create($data) - { - $anrId = (int) $this->params()->fromRoute('anrid'); - $instanceId = (int)$this->params()->fromRoute("instanceid"); - return new JsonModel([ - 'status' => 'ok', - 'id' => $this->instanceMetadataService->createInstanceMetadata($anrId, $instanceId, $data), - ]); - } - public function getList() { - $anrId = (int) $this->params()->fromRoute('anrid'); - $language = $this->params()->fromQuery("language"); - $instanceId = (int)$this->params()->fromRoute("instanceid"); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $instanceId = (int)$this->params()->fromRoute('instanceid'); - return new JsonModel([ - 'data' => $this->instanceMetadataService->getInstancesMetadatas($anrId, $instanceId, $language), + return $this->getSuccessfulJsonResponse([ + 'data' => $this->instanceMetadataService->getInstancesMetadata($anr, $instanceId), ]); } - public function delete($id) + /** + * @param array $data + */ + public function create($data) { - $this->instanceMetadataService->deleteInstanceMetadata($id); - - return new JsonModel(['status' => 'ok']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $instanceId = (int)$this->params()->fromRoute('instanceid'); - public function get($id) - { - $anrId = (int) $this->params()->fromRoute('anrid'); - return new JsonModel([ - 'data' => $this->instanceMetadataService->getInstanceMetadata($anrId, $id), + return $this->getSuccessfulJsonResponse([ + 'id' => $this->instanceMetadataService->create($anr, $instanceId, $data)->getId(), ]); } + /** + * @param array $data + */ public function update($id, $data) { - if ($this->instanceMetadataService->update((int)$id, $data)) { - return new JsonModel(['status' => 'ok']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->instanceMetadataService->update($anr, (int)$id, $data); - return new JsonModel(['status' => 'ko']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiModelVerifyLanguageController.php b/src/Controller/ApiModelVerifyLanguageController.php index 9c469cfa..55ecacb9 100755 --- a/src/Controller/ApiModelVerifyLanguageController.php +++ b/src/Controller/ApiModelVerifyLanguageController.php @@ -1,70 +1,24 @@ -getService()->verifyLanguage($id); - - return new JsonModel($result); } - /** - * @inheritdoc - */ - public function getList() - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function create($data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function patch($token, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) + public function get($id) { - return $this->methodNotAllowed(); + return new JsonModel($this->anrModelService->getAvailableLanguages((int)$id)); } } diff --git a/src/Controller/ApiModelVerifyLanguageControllerFactory.php b/src/Controller/ApiModelVerifyLanguageControllerFactory.php deleted file mode 100755 index 11f9946b..00000000 --- a/src/Controller/ApiModelVerifyLanguageControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $isGeneric = $this->params()->fromQuery('isGeneric'); - $status = (string)$this->params()->fromQuery('status', \Monarc\Core\Model\Entity\AbstractEntity::STATUS_ACTIVE); - - $service = $this->getService(); - switch ($status) { - case (string)\Monarc\Core\Model\Entity\AbstractEntity::STATUS_INACTIVE: - $filterAnd = ['status' => \Monarc\Core\Model\Entity\AbstractEntity::STATUS_INACTIVE]; - break; - default: - case (string)\Monarc\Core\Model\Entity\AbstractEntity::STATUS_ACTIVE: - $filterAnd = ['status' => \Monarc\Core\Model\Entity\AbstractEntity::STATUS_ACTIVE]; - break; - case 'all': - $filterAnd = ['status' => ['op' => 'IN', 'value' => [\Monarc\Core\Model\Entity\AbstractEntity::STATUS_INACTIVE, \Monarc\Core\Model\Entity\AbstractEntity::STATUS_ACTIVE]]]; - break; - } - - - if (!is_null($isGeneric)) { - $filterAnd['isGeneric'] = $isGeneric; - } - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd, 'FO'); - - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } - - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - ]); } - /** - * @inheritdoc - */ - public function get($id) + public function getList() { - /** @var ModelService $modelService */ - $modelService = $this->getService(); - $entity = $modelService->getModelWithAnr($id); - - return new JsonModel($entity); + return $this->getPreparedJsonResponse(['models' => $this->anrModelService->getModelsListOfClient()]); } } diff --git a/src/Controller/ApiModelsControllerFactory.php b/src/Controller/ApiModelsControllerFactory.php deleted file mode 100755 index 8359b607..00000000 --- a/src/Controller/ApiModelsControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -operationalRiskScaleCommentService = $operationalRiskScaleCommentService; } + /** + * @param array $data + */ public function update($id, $data) { - $data['anr'] = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if ($this->operationalRiskScaleCommentService->update((int)$id, $data)) { - return new JsonModel(['status' => 'ok']); - } + $this->operationalRiskScaleCommentService->update($anr, (int)$id, $data); - return new JsonModel(['status' => 'ko']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiOperationalRisksScalesController.php b/src/Controller/ApiOperationalRisksScalesController.php index 13580ae5..a45399fc 100644 --- a/src/Controller/ApiOperationalRisksScalesController.php +++ b/src/Controller/ApiOperationalRisksScalesController.php @@ -1,14 +1,22 @@ params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'data' => $this->operationalRiskScaleService->getOperationalRiskScales($anrId), + return $this->getPreparedJsonResponse([ + 'data' => $this->operationalRiskScaleService->getOperationalRiskScales($anr), ]); } + /** + * @param array $data + */ public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'status' => 'ok', - 'id' => $this->operationalRiskScaleService->createOperationalRiskScaleType($anrId, $data), + return $this->getSuccessfulJsonResponse([ + 'id' => $this->operationalRiskScaleService->createOperationalRiskScaleType($anr, $data)->getId(), ]); } - public function deleteList($data) - { - $this->operationalRiskScaleService->deleteOperationalRiskScaleTypes($data); - - return new JsonModel(['status' => 'ok']); - } - + /** + * @param array $data + */ public function update($id, $data) { - $data['anr'] = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if ($this->operationalRiskScaleService->update((int)$id, $data)) { - return new JsonModel(['status' => 'ok']); - } + $this->operationalRiskScaleService->updateScaleType($anr, (int)$id, $data); - // Not successful - return new JsonModel(['status' => 'ko']); + return $this->getSuccessfulJsonResponse(); } public function patchList($data) { - $data['anr'] = (int)$this->params()->fromRoute('anrid'); + // TODO: add a validator for the limits... + + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); if (isset($data['scaleValue'], $data['scaleIndex'])) { - $this->operationalRiskScaleService->updateValueForAllScales($data); + $this->operationalRiskScaleService->updateValueForAllScales($anr, $data); } if (isset($data['numberOfLevelForOperationalImpact'])) { @@ -69,7 +78,7 @@ public function patchList($data) throw new Exception('Scales level must remain below 20 ', 412); } - $this->operationalRiskScaleService->updateLevelsNumberOfOperationalRiskScale($data); + $this->operationalRiskScaleService->updateLevelsNumberOfOperationalRiskScale($anr, $data); } if (isset($data['probabilityMin'], $data['probabilityMax'])) { @@ -83,9 +92,19 @@ public function patchList($data) throw new Exception('Minimum cannot be greater than Maximum', 412); } - $this->operationalRiskScaleService->updateMinMaxForOperationalRiskProbability($data); + $this->operationalRiskScaleService->updateMinMaxForOperationalRiskProbability($anr, $data); } - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); + } + + public function deleteList($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->operationalRiskScaleService->deleteOperationalRiskScaleTypes($anr, $data); + + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiReferentialsController.php b/src/Controller/ApiReferentialsController.php deleted file mode 100644 index 71f3d452..00000000 --- a/src/Controller/ApiReferentialsController.php +++ /dev/null @@ -1,38 +0,0 @@ -anrReferentialService = $anrReferentialService; - } - - /** - * Is used in analysis creation. - */ - public function getList() - { - $filter = $this->params()->fromQuery('filter'); - $order = $this->params()->fromQuery('order'); - - $referentials = $this->anrReferentialService->getCommonReferentials($filter, $order); - - return new JsonModel([ - 'count' => \count($referentials), - 'referentials' => $referentials, - ]); - } -} diff --git a/src/Controller/ApiSnapshotController.php b/src/Controller/ApiSnapshotController.php index 173eef49..08e43fe4 100755 --- a/src/Controller/ApiSnapshotController.php +++ b/src/Controller/ApiSnapshotController.php @@ -1,69 +1,61 @@ -params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status'); + $this->snapshotService = $snapshotService; + } - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } + public function getList() + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $filterAnd = ['anrReference' => $anrId]; + $snapshotsList = $this->snapshotService->getList($anr); - if (!is_null($status) && $status != 'all') { - $filterAnd['status'] = $status; - } + return $this->getPreparedJsonResponse([ + 'count' => \count($snapshotsList), + 'snapshots' => $snapshotsList, + ]); + } - $service = $this->getService(); + /** + * @param array $data + */ + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } + $snapshot = $this->snapshotService->create($anr, $data); - return new JsonModel([ - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - ]); + return $this->getSuccessfulJsonResponse(['id' => $snapshot->getId()]); } public function delete($id) { - if ($this->getService()->delete($id)) { - return new JsonModel(['status' => 'ok']); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->snapshotService->delete($anr, (int)$id); - return new JsonModel(['status' => 'ok']); // Todo : may be add error message + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiSnapshotControllerFactory.php b/src/Controller/ApiSnapshotControllerFactory.php deleted file mode 100644 index 69426c10..00000000 --- a/src/Controller/ApiSnapshotControllerFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new \Monarc\Core\Exception\Exception('Anr id missing', 412); - } + use ControllerRequestResponseHandlerTrait; - $id = (int)$this->params()->fromRoute('id'); - if (empty($id)) { - throw new \Monarc\Core\Exception\Exception('Snapshot id missing', 412); - } + private SnapshotService $snapshotService; - /** @var SnapshotService $service */ - $service = $this->getService(); - $newId = $service->restore($anrId, $id); - - return new JsonModel([ - 'status' => 'ok', - 'id' => $newId, - ]); - } - - /** - * @inheritdoc - */ - public function getList() + public function __construct(SnapshotService $snapshotService) { - return $this->methodNotAllowed(); + $this->snapshotService = $snapshotService; } - /** - * @inheritdoc - */ - public function get($id) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function delete($id) + public function create($data) { - return $this->methodNotAllowed(); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $snapshotId = (int)$this->params()->fromRoute('id'); - /** - * @inheritdoc - */ - public function deleteList($data) - { - return $this->methodNotAllowed(); - } + $newAnr = $this->snapshotService->restore($anr, $snapshotId); - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->methodNotAllowed(); - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - return $this->methodNotAllowed(); + return $this->getSuccessfulJsonResponse(['id' => $newAnr->getId()]); } } diff --git a/src/Controller/ApiSnapshotRestoreControllerFactory.php b/src/Controller/ApiSnapshotRestoreControllerFactory.php deleted file mode 100755 index 20a36329..00000000 --- a/src/Controller/ApiSnapshotRestoreControllerFactory.php +++ /dev/null @@ -1,21 +0,0 @@ -getPreparedJsonResponse([ + 'categories' => $this->soaCategoryService->getList( + $this->getFormattedInputParams($this->getSoaCategoriesInputFormatter) + ), + ]); + } + + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->soaCategoryService->getSoaCategoryData($anr, (int)$id)); + } /** - * @inheritdoc + * @param array $data */ - public function getList() + public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - $page = $this->params()->fromQuery('page'); - $limit = $this->params()->fromQuery('limit'); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $status = $this->params()->fromQuery('status', 1); - $referential = $this->params()->fromQuery('referential'); - - $filterAnd = ['anr' => $anrId]; - if ($status === 'all') { - $filterAnd['status'] = (int)$status; - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $isBatchData = $this->isBatchData($data); + $this->validatePostParams($this->postSoaCategoryDataInputValidator, $data, $isBatchData); - if ($referential) { - $filterAnd['r.anr'] = $anrId; - $filterAnd['r.uuid'] = $referential; + if ($isBatchData) { + return $this->getSuccessfulJsonResponse([ + 'id' => $this->soaCategoryService + ->createList($anr, $this->postSoaCategoryDataInputValidator->getValidDataSets()), + ]); } - $service = $this->getService(); + return $this->getSuccessfulJsonResponse([ + 'id' => $this->soaCategoryService->create($anr, $this->postSoaCategoryDataInputValidator->getValidData()) + ->getId(), + ]); + } - $entities = $service->getList($page, $limit, $order, $filter, $filterAnd); - if (count($this->dependencies)) { - foreach ($entities as $key => $entity) { - $this->formatDependencies($entities[$key], $this->dependencies); - } - } + /** + * @param array $data + */ + public function update($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->validatePostParams($this->postSoaCategoryDataInputValidator, $data); + + $this->soaCategoryService->update($anr, (int)$id, $this->postSoaCategoryDataInputValidator->getValidData()); + + return $this->getSuccessfulJsonResponse(); + } + + public function delete($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->soaCategoryService->delete($anr, (int)$id); - return new JsonModel(array( - 'count' => $service->getFilteredCount($filter, $filterAnd), - $this->name => $entities - )); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Controller/ApiSoaCategoryControllerFactory.php b/src/Controller/ApiSoaCategoryControllerFactory.php deleted file mode 100755 index cd055e8b..00000000 --- a/src/Controller/ApiSoaCategoryControllerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -soaService = $soaService; - $this->anrMeasureService = $anrMeasureService; - $this->anrInstanceRiskService = $anrInstanceRiskService; - $this->anrInstanceRiskOpService = $anrInstanceRiskOpService; - $this->soaScaleCommentService = $soaScaleCommentService; + public function __construct(private SoaService $soaService, private GetSoasInputFormatter $getSoasInputFormatter) + { } public function getList() { - $page = (int)$this->params()->fromQuery('page', 1); - $limit = (int)$this->params()->fromQuery('limit', 0); - $order = $this->params()->fromQuery('order'); - $filter = $this->params()->fromQuery('filter'); - $category = (int)$this->params()->fromQuery('category', 0); - $referential = $this->params()->fromQuery('referential'); - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - $filterAnd = ['anr' => $anrId]; - - if ($referential) { - if ($category !== 0) { - $filterMeasures['category'] = [ - 'op' => 'IN', - 'value' => (array)$category, - ]; - } elseif ($category === -1) { - $filterMeasures['category'] = null; - } - - $filterMeasures['r.anr'] = $anrId; - $filterMeasures['r.uuid'] = $referential; - - $measuresFiltered = $this->anrMeasureService->getList(1, 0, null, null, $filterMeasures); - $measuresFilteredId = []; - foreach ($measuresFiltered as $key) { - $measuresFilteredId[] = $key['uuid']; - } - $filterAnd['m.uuid'] = [ - 'op' => 'IN', - 'value' => $measuresFilteredId, - ]; - $filterAnd['m.anr'] = $anrId; - } - - if ($order === 'measure') { - $order = 'm.code'; - } elseif ($order === '-measure') { - $order = '-m.code'; - } - $soaScaleCommentsData = $this->soaScaleCommentService->getSoaScaleCommentsDataById($anrId); - $entities = $this->soaService->getList($page, $limit, $order, $filter, $filterAnd); - foreach ($entities as $key => $entity) { - $amvs = []; - $rolfRisks = []; - - /** @var SoaScaleComment $measure */ - $soaScaleComment = $entity['soaScaleComment']; - - /** @var Measure $measure */ - $measure = $entity['measure']; - foreach ($measure->getAmvs() as $amv) { - $amvs[] = $amv->getUuid(); - } - foreach ($measure->getRolfRisks() as $rolfRisk) { - $rolfRisks[] = $rolfRisk->getId(); - } - $entity['measure']->rolfRisks = []; - if (!empty($rolfRisks)) { - $entity['measure']->rolfRisks = $this->anrInstanceRiskOpService->getOperationalRisks($anrId, null, [ - 'rolfRisks' => $rolfRisks, - 'limit' => -1, - 'order' => 'cacheNetRisk', - 'order_direction' => 'desc', - ]); - } - $entity['measure']->amvs = []; - if (!empty($amvs)) { - $entity['measure']->amvs = $this->anrInstanceRiskService->getInstanceRisks($anrId, null, [ - 'amvs' => $amvs, - 'limit' => -1, - 'order' => 'maxRisk', - 'order_direction' => 'desc', - ]); - } - $entities[$key]['anr'] = $measure->getAnr()->getJsonArray(); - $entities[$key]['measure'] = $measure->getJsonArray(); - $entities[$key]['measure']['category'] = $measure->getCategory()->getJsonArray(); - $entities[$key]['measure']['referential'] = $measure->getReferential()->getJsonArray(); - $entities[$key]['measure']['measuresLinked'] = []; - foreach ($measure->getMeasuresLinked() as $measureLinked) { - $entities[$key]['measure']['measuresLinked'][] = $measureLinked->getUuid(); - } - if ($soaScaleComment !== null) { - $entities[$key]['soaScaleComment'] = $soaScaleCommentsData[$soaScaleComment->getId()]; - } else { - $entities[$key]['soaScaleComment'] = null; - } - } - - return new JsonModel([ - 'count' => $this->soaService->getFilteredCount($filter, $filterAnd), - 'soaMeasures' => $entities, + return $this->getPreparedJsonResponse([ + 'soaMeasures' => $this->soaService->getList($this->getFormattedInputParams($this->getSoasInputFormatter)), + 'count' => $this->soaService->getCount($this->getFormattedInputParams($this->getSoasInputFormatter)) ]); } - public function get($id) - { - $entity = $this->soaService->getEntity($id); - /** @var Measure $measure */ - $measure = $entity['measure']; - /** @var SoaScaleComment $measure */ - $soaScaleComment = $entity['soaScaleComment']; - - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('"anrid" param is missing', 412); - } - if ($measure->getAnr()->getId() !== $anrId) { - throw new Exception('Anr IDs are different', 412); - } - - $soaScaleCommentsData = $this->soaScaleCommentService->getSoaScaleCommentsDataById($anrId); - - $entity['anr'] = $measure->getAnr()->getJsonArray(); - $entity['measure'] = $measure->getJsonArray(); - $entity['measure']['category'] = $measure->getCategory()->getJsonArray(); - $entity['measure']['referential'] = $measure->getReferential()->getJsonArray(); - if ($soaScaleComment !== null) { - $entities['soaScaleComment'] = $soaScaleCommentsData[$soaScaleComment->getId()]; - } else { - $entities['soaScaleComment'] = null; - } - - return new JsonModel($entity); - } - public function patch($id, $data) { - $this->soaService->patchSoa($id, $data); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + $this->soaService->patchSoa($anr, (int)$id, $data); - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } public function patchList($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - - $createdObjects = []; - foreach ($data as $newData) { - $newData['anr'] = $anrId; - $newData['measure'] = ['anr' => $anrId, 'uuid' => $newData['measure']['uuid']]; - $id = $newData['id']; - if (is_array($newData['soaScaleComment'])) { - $newData['soaScaleComment'] = $newData['soaScaleComment']['id']; - } - $this->soaService->patchSoa($id, $newData); - $createdObjects[] = $id; - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'status' => 'ok', - 'id' => $createdObjects, - ]); + return $this->getSuccessfulJsonResponse(['id' => $this->soaService->patchList($anr, $data)]); } } diff --git a/src/Controller/ApiSoaScaleCommentController.php b/src/Controller/ApiSoaScaleCommentController.php index 1aa85cbb..62a7494a 100644 --- a/src/Controller/ApiSoaScaleCommentController.php +++ b/src/Controller/ApiSoaScaleCommentController.php @@ -1,49 +1,57 @@ soaScaleCommentService = $soaScaleCommentService; } public function getList() { - $anrId = (int) $this->params()->fromRoute('anrid'); - $language = $this->params()->fromQuery("language"); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ - 'data' => $this->soaScaleCommentService->getSoaScaleComments($anrId, $language), + return $this->getPreparedJsonResponse([ + 'data' => $this->soaScaleCommentService->getSoaScaleCommentsData($anr), ]); } + /** + * @param array $data + */ public function update($id, $data) { - $data['anr'] = (int)$this->params()->fromRoute('anrid'); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - if ($this->soaScaleCommentService->update((int)$id, $data)) { - return new JsonModel(['status' => 'ok']); - } + $this->soaScaleCommentService->update($anr, (int)$id, $data); - return new JsonModel(['status' => 'ko']); + return $this->getSuccessfulJsonResponse(); } public function patchList($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - $language = $this->params()->fromQuery("language"); - $this->soaScaleCommentService->createOrHideSoaScaleComment($anrId, $data); - return new JsonModel([ - 'data' => $this->soaScaleCommentService->getSoaScaleComments($anrId, $language), + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $this->soaScaleCommentService->createOrHideSoaScaleComments($anr, $data); + + return $this->getSuccessfulJsonResponse([ + 'data' => $this->soaScaleCommentService->getSoaScaleCommentsData($anr), ]); } } diff --git a/src/Controller/ApiSystemMessagesController.php b/src/Controller/ApiSystemMessagesController.php new file mode 100755 index 00000000..d661f498 --- /dev/null +++ b/src/Controller/ApiSystemMessagesController.php @@ -0,0 +1,41 @@ +systemMessageService->getListOfActiveMessages(); + + return $this->getPreparedJsonResponse([ + 'count' => \count($messages), + 'messages' => $messages, + ]); + } + + /** + * @param int $id + */ + public function delete($id) + { + $this->systemMessageService->inactivateMessage((int)$id); + + return $this->getSuccessfulJsonResponse(); + } +} diff --git a/src/Controller/ApiUserPasswordController.php b/src/Controller/ApiUserPasswordController.php index d1a1be3a..ef12e0e1 100755 --- a/src/Controller/ApiUserPasswordController.php +++ b/src/Controller/ApiUserPasswordController.php @@ -1,7 +1,7 @@ -passwordService = $passwordService; } public function update($id, $data) @@ -34,7 +24,7 @@ public function update($id, $data) throw new Exception('Password must be the same', 422); } - $this->passwordService->changePassword($id, $data['old'], $data['new']); + $this->passwordService->changePassword((int)$id, $data['old'], $data['new']); return new JsonModel(['status' => 'ok']); } diff --git a/src/Controller/ApiUserProfileController.php b/src/Controller/ApiUserProfileController.php index 3fda7b16..0badd1d3 100755 --- a/src/Controller/ApiUserProfileController.php +++ b/src/Controller/ApiUserProfileController.php @@ -1,90 +1,74 @@ -userProfileService = $userProfileService; - $this->connectedUserService = $connectedUserService; + public function __construct( + private PatchProfileDataInputValidator $patchProfileDataInputValidator, + private UserProfileService $userProfileService, + ConnectedUserService $connectedUserService + ) { + $this->connectedUser = $connectedUserService->getConnectedUser(); } public function getList() { - $connectedUser = $this->connectedUserService->getConnectedUser(); - if ($connectedUser === null) { - throw new Exception('You are not authorized to do this action', 412); - } - - // TODO: We need to use normalizer for the response fields filtering out. return new JsonModel([ - 'id' => $connectedUser->getId(), - 'firstname' => $connectedUser->getFirstname(), - 'lastname' => $connectedUser->getLastname(), - 'email' => $connectedUser->getEmail(), - 'status' => $connectedUser->getStatus(), - 'role' => $connectedUser->getRoles(), - 'isTwoFactorAuthEnabled' => $connectedUser->isTwoFactorAuthEnabled(), - 'remainingRecoveryCodes' => \count($connectedUser->getRecoveryCodes()), - 'mospApiKey' => $connectedUser->getMospApiKey(), + 'id' => $this->connectedUser->getId(), + 'firstname' => $this->connectedUser->getFirstname(), + 'lastname' => $this->connectedUser->getLastname(), + 'email' => $this->connectedUser->getEmail(), + 'status' => $this->connectedUser->getStatus(), + 'role' => $this->connectedUser->getRolesArray(), + 'isTwoFactorAuthEnabled' => $this->connectedUser->isTwoFactorAuthEnabled(), + 'remainingRecoveryCodes' => \count($this->connectedUser->getRecoveryCodes()), + 'mospApiKey' => $this->connectedUser->getMospApiKey(), ]); } - /** - * @inheritdoc - */ public function patchList($data) { - $this->userProfileService->update($this->connectedUserService->getConnectedUser(), $data); + $this->validatePostParams( + $this->patchProfileDataInputValidator->setExcludeFilter(['email' => $this->connectedUser->getEmail()]), + $data + ); + + $this->userProfileService->updateMyData($data); - // Replace to return the updated object. - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ public function replaceList($data) { - $this->userProfileService->update($this->connectedUserService->getConnectedUser(), $data); + $this->userProfileService->updateMyData($data); - // Replace to return the updated object. - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } - /** - * @inheritdoc - */ - public function deleteList($id) + public function deleteList($data) { - $this->userProfileService->delete($this->connectedUserService->getConnectedUser()->getId()); + $this->userProfileService->deleteMe(); $this->getResponse()->setStatusCode(204); - return new JsonModel(); + return $this->getPreparedJsonResponse(); } } diff --git a/src/Controller/ApiUserRecoveryCodesController.php b/src/Controller/ApiUserRecoveryCodesController.php index 726ceb58..e2792685 100644 --- a/src/Controller/ApiUserRecoveryCodesController.php +++ b/src/Controller/ApiUserRecoveryCodesController.php @@ -1,68 +1,51 @@ -userService = $userService; - $this->connectedUserService = $connectedUserService; - $this->userTable = $userTable; + public function __construct(private UserTable $userTable, ConnectedUserService $connectedUserService) + { + /** @var User $user */ + $user = $connectedUserService->getConnectedUser(); + $this->connectedUser = $user; } /** - * Generates and returns 5 new recovery codes (20 chars for each codes). + * Generates and returns 5 new recovery codes (20 chars for each code). */ public function create($data) { - $connectedUser = $this->connectedUserService->getConnectedUser(); $status = 'ok'; - if (! $connectedUser->isTwoFactorAuthEnabled()) { - $status = 'Two factor authentication not enbabled'; - } else { - $recoveryCodes = array(); + if ($this->connectedUser->isTwoFactorAuthEnabled()) { + $recoveryCodes = []; for ($i = 0; $i < 5; $i++) { - array_push($recoveryCodes, bin2hex(openssl_random_pseudo_bytes(10))); + $recoveryCodes[] = bin2hex(openssl_random_pseudo_bytes(10)); } - $connectedUser->createRecoveryCodes($recoveryCodes); - $this->userTable->saveEntity($connectedUser); + $this->connectedUser->createRecoveryCodes($recoveryCodes); + $this->userTable->save($this->connectedUser); + } else { + $status = 'Two factor authentication not enbabled'; } - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'status' => $status, 'recoveryCodes' => $recoveryCodes, ]); diff --git a/src/Controller/ApiUserTwoFAController.php b/src/Controller/ApiUserTwoFAController.php index 07a2d15a..0b9f4ab3 100644 --- a/src/Controller/ApiUserTwoFAController.php +++ b/src/Controller/ApiUserTwoFAController.php @@ -1,55 +1,38 @@ -configService = $configService; - $this->userService = $userService; - $this->connectedUserService = $connectedUserService; - $this->userTable = $userTable; + /** @var User $connectedUser */ + $connectedUser = $connectedUserService->getConnectedUser(); + $this->connectedUser = $connectedUser; $qr = new EndroidQrCodeProvider(); $this->tfa = new TwoFactorAuth('MONARC', 6, 30, 'sha1', $qr); } @@ -60,11 +43,11 @@ public function __construct( */ public function get($id) { - $connectedUser = $this->connectedUserService->getConnectedUser(); - if ($connectedUser === null) { + if ($this->connectedUser === null) { throw new Exception('You are not authorized to do this action', 412); } + // TODO: move to the service... // Create a new secret and generate a QRCode $label = 'MONARC'; if ($this->configService->getInstanceName()) { @@ -73,8 +56,8 @@ public function get($id) $secret = $this->tfa->createSecret(); $qrcode = $this->tfa->getQRCodeImageAsDataUri($label, $secret); - return new JsonModel([ - 'id' => $connectedUser->getId(), + return $this->getPreparedJsonResponse([ + 'id' => $this->connectedUser->getId(), 'secret' => $secret, 'qrcode' => $qrcode, ]); @@ -83,19 +66,21 @@ public function get($id) /** * Confirms the newly generated key with a token given by the user. * This is just good practice. + * + * @param array $data */ public function create($data) { - $connectedUser = $this->connectedUserService->getConnectedUser(); + // TODO: move to the service... $res = $this->tfa->verifyCode($data['secretKey'], $data['verificationCode']); if ($res) { - $connectedUser->setSecretKey($data['secretKey']); - $connectedUser->setTwoFactorAuthEnabled(true); - $this->userTable->saveEntity($connectedUser); + $this->connectedUser->setSecretKey($data['secretKey']); + $this->connectedUser->setTwoFactorAuthEnabled(true); + $this->userTable->save($this->connectedUser); } - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'status' => $res, ]); } @@ -106,18 +91,18 @@ public function create($data) */ public function delete($id) { - $connectedUser = $this->connectedUserService->getConnectedUser(); - if ($connectedUser === null) { + if ($this->connectedUser === null) { throw new Exception('You are not authorized to do this action', 412); } - $connectedUser->setTwoFactorAuthEnabled(false); - $connectedUser->setSecretKey(null); - $connectedUser->setRecoveryCodes(null); - $this->userTable->saveEntity($connectedUser); + // TODO: move to the service. + $this->connectedUser->setTwoFactorAuthEnabled(false); + $this->connectedUser->setSecretKey(''); + $this->connectedUser->setRecoveryCodes([]); + $this->userTable->save($this->connectedUser); $this->getResponse()->setStatusCode(204); - return new JsonModel(); + return $this->getPreparedJsonResponse(); } } diff --git a/src/CronTask/Service/CronTaskService.php b/src/CronTask/Service/CronTaskService.php index 48645184..fb0ab7c6 100644 --- a/src/CronTask/Service/CronTaskService.php +++ b/src/CronTask/Service/CronTaskService.php @@ -8,10 +8,10 @@ namespace Monarc\FrontOffice\CronTask\Service; use DateTime; -use Monarc\Core\Model\Entity\UserSuperClass; +use Monarc\Core\Entity\UserSuperClass; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\CronTask\Table\CronTaskTable; -use Monarc\FrontOffice\Model\Entity\CronTask; +use Monarc\FrontOffice\Entity\CronTask; class CronTaskService { diff --git a/src/CronTask/Table/CronTaskTable.php b/src/CronTask/Table/CronTaskTable.php index 324e4cbd..c870425d 100644 --- a/src/CronTask/Table/CronTaskTable.php +++ b/src/CronTask/Table/CronTaskTable.php @@ -10,8 +10,8 @@ use DateTime; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\EntityManager; -use Monarc\Core\Model\Table\AbstractTable; -use Monarc\FrontOffice\Model\Entity\CronTask; +use Monarc\Core\Table\AbstractTable; +use Monarc\FrontOffice\Entity\CronTask; class CronTaskTable extends AbstractTable { diff --git a/src/Model/Entity/Amv.php b/src/Entity/Amv.php similarity index 63% rename from src/Model/Entity/Amv.php rename to src/Entity/Amv.php index 49208833..7f1613ba 100755 --- a/src/Model/Entity/Amv.php +++ b/src/Entity/Amv.php @@ -1,21 +1,17 @@ -instanceRisks = new ArrayCollection(); - $this->measures = new ArrayCollection(); - - parent::__construct($obj); + return [ + 'anr' => $this->anr, + 'asset' => [ + 'uuid' => $this->asset->getUuid(), + 'anr' => $this->anr, + ] + ]; } - public function getInstanceRisks() + public function getAnr(): Anr { - return $this->instanceRisks; + return $this->anr; } - public function getInputFilter($partial = false) + public function setAnr(Anr $anr): self { - if (!$this->inputFilter) { - parent::getInputFilter($partial); - } + $this->anr = $anr; - return $this->inputFilter; + return $this; } } diff --git a/src/Entity/Anr.php b/src/Entity/Anr.php new file mode 100755 index 00000000..b8faa1dc --- /dev/null +++ b/src/Entity/Anr.php @@ -0,0 +1,483 @@ +objects = new ArrayCollection(); + $this->objectCategories = new ArrayCollection(); + $this->referentials = new ArrayCollection(); + $this->referencedSnapshots = new ArrayCollection(); + $this->usersAnrsPermissions = new ArrayCollection(); + $this->recommendationSets = new ArrayCollection(); + } + + /** + * Only the primitive data types properties values are set to the new object. + * The relation properties have to be recreated manually. + * + * @return Anr + */ + public static function constructFromObjectAndData(AnrSuperClass $sourceAnr, array $data): AnrSuperClass + { + /** @var Anr $newAnr */ + $newAnr = parent::constructFromObject($sourceAnr); + + if ($sourceAnr instanceof self) { + /* Duplication of a FrontOffice analysis, creation of a snapshot or restoring it. + * For snapshots we use tha same label and description (label [SNAP] prefix will be added later). */ + $newAnr->setLabel($data['label'] ?? $sourceAnr->getLabel()) + ->setDescription($data['description'] ?? $sourceAnr->getDescription()) + ->setLanguage($sourceAnr->getLanguage()) + ->setLanguageCode($sourceAnr->getLanguageCode()) + ->setIsVisibleOnDashboard((int)$sourceAnr->isVisibleOnDashboard()) + ->setIsStatsCollected((int)$sourceAnr->isStatsCollected()) + ->setModelId($sourceAnr->getModelId()) + ->setCacheModelAreScalesUpdatable($sourceAnr->getCacheModelAreScalesUpdatable()) + ->setCacheModelShowRolfBrut($sourceAnr->getCacheModelShowRolfBrut()); + } elseif ($sourceAnr instanceof AnrCore) { + /* Creation of an analysis based on a model. */ + $languageIndex = (int)($data['language'] ?? 1); + $newAnr->setLabel((string)$data['label']) + ->setDescription((string)$data['description']) + ->setLanguage($languageIndex) + ->setLanguageCode($data['languageCode'] ?? 'fr') + ->setModelId($sourceAnr->getModel()->getId()) + ->setCacheModelShowRolfBrut($sourceAnr->getModel()->showRolfBrut()) + ->setCacheModelAreScalesUpdatable($sourceAnr->getModel()->areScalesUpdatable()); + } else { + throw new \LogicException('The analysis can not be created due to the logic error.'); + } + + return $newAnr; + } + + public function getLabel(): string + { + return $this->label; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } + + public function getDescription(): string + { + return (string)$this->description; + } + + public function setDescription(string $description): self + { + $this->description = $description; + + return $this; + } + + public function setLanguage($language): self + { + $this->language = $language; + + return $this; + } + + public function getLanguage(): int + { + return $this->language; + } + + /** + * @ORM\PrePersist + */ + public function generateAndSetUuid(): self + { + $this->uuid = Uuid::uuid4(); + + return $this; + } + + public function getUuid(): string + { + return (string)$this->uuid; + } + + public function setUuid(string $uuid): self + { + $this->uuid = $uuid; + + return $this; + } + + public function isVisibleOnDashboard(): bool + { + return (bool)$this->isVisibleOnDashboard; + } + + public function setIsVisibleOnDashboard(int $isVisibleOnDashboard): self + { + $this->isVisibleOnDashboard = $isVisibleOnDashboard; + + return $this; + } + + public function isStatsCollected(): bool + { + return (bool)$this->isStatsCollected; + } + + public function setIsStatsCollected(int $isStatsCollected): self + { + $this->isStatsCollected = $isStatsCollected; + + return $this; + } + + public function setModelId(int $modelId): self + { + $this->modelId = $modelId; + + return $this; + } + + public function getModelId(): ?int + { + return $this->modelId; + } + + public function getModelImpacts(): int + { + return $this->modelImpacts; + } + + public function setModelImpacts(int $modelImpacts): self + { + $this->modelImpacts = $modelImpacts; + + return $this; + } + + public function getCacheModelAreScalesUpdatable(): bool + { + return (bool)$this->cacheModelAreScalesUpdatable; + } + + public function setCacheModelAreScalesUpdatable(bool $cacheModelAreScalesUpdatable): self + { + $this->cacheModelAreScalesUpdatable = $cacheModelAreScalesUpdatable; + + return $this; + } + + public function getObjects() + { + return $this->objects; + } + + public function addObject(MonarcObject $object): self + { + if (!$this->objects->contains($object)) { + $this->objects->add($object); + $object->setAnr($this); + } + + return $this; + } + + public function getObjectCategories() + { + return $this->objectCategories; + } + + public function addObjectCategory(ObjectCategory $objectCategory): self + { + if (!$this->objectCategories->contains($objectCategory)) { + $this->objectCategories->add($objectCategory); + $objectCategory->setAnr($this); + } + + return $this; + } + + public function getReferentials() + { + return $this->referentials; + } + + public function addReferential(Referential $referential): self + { + if (!$this->referentials->contains($referential)) { + $this->referentials->add($referential); + $referential->setAnr($this); + } + + return $this; + } + + public function removeReferential(Referential $referential): self + { + if ($this->referentials->contains($referential)) { + $this->referentials->removeElement($referential); + } + + return $this; + } + + public function getReferencedSnapshots() + { + return $this->referencedSnapshots; + } + + public function addReferencedSnapshot(Snapshot $snapshot): self + { + if (!$this->referencedSnapshots->contains($snapshot)) { + $this->referencedSnapshots->add($snapshot); + $snapshot->setAnrReference($this); + } + + 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; + } + + public function addRecommendationSet(RecommendationSet $recommendationSet): self + { + if (!$this->recommendationSets->contains($recommendationSet)) { + $this->recommendationSets->add($recommendationSet); + $recommendationSet->setAnr($this); + } + + return $this; + } + + public function isAnrSnapshot(): bool + { + return $this->snapshot !== null; + } + + public function getSnapshot(): ?Snapshot + { + return $this->snapshot; + } + + public function setSnapshot(Snapshot $snapshot): self + { + $this->snapshot = $snapshot; + $snapshot->setAnr($this); + + return $this; + } + + public function getLanguageCode(): string + { + return $this->languageCode; + } + + public function setLanguageCode(string $languageCode): self + { + $this->languageCode = $languageCode; + + return $this; + } + + public function getUsersAnrsPermissions() + { + return $this->usersAnrsPermissions; + } + + public function addUserAnrPermission(UserAnr $userAnrPermission): self + { + if (!$this->usersAnrsPermissions->contains($userAnrPermission)) { + $this->usersAnrsPermissions->add($userAnrPermission); + $userAnrPermission->setAnr($this); + } + + return $this; + } + + public function removeUserAnrPermission(UserAnr $userAnrPermission): self + { + if ($this->usersAnrsPermissions->contains($userAnrPermission)) { + $this->usersAnrsPermissions->removeElement($userAnrPermission); + } + + return $this; + } + + public function getInformationalRiskLevelColor(int $riskValue): string + { + if ($riskValue <= $this->seuil1) { + return 'green'; + } + if ($riskValue <= $this->seuil2) { + return 'orange'; + } + + return 'alerte'; + } + + public function getOperationalRiskLevelColor(int $riskValue): string + { + if ($riskValue <= $this->seuilRolf1) { + return 'green'; + } + if ($riskValue <= $this->seuilRolf2) { + return 'orange'; + } + + return 'alerte'; + } +} diff --git a/src/Entity/AnrInstanceMetadataField.php b/src/Entity/AnrInstanceMetadataField.php new file mode 100644 index 00000000..cd50b289 --- /dev/null +++ b/src/Entity/AnrInstanceMetadataField.php @@ -0,0 +1,95 @@ +instancesMetadata = new ArrayCollection(); + } + + public function isDeletable(): bool + { + return (bool)$this->isDeletable; + } + + public function setIsDeletable(bool $isDeletable): self + { + $this->isDeletable = (int)$isDeletable; + + return $this; + } + + public function getInstancesMetadata() + { + return $this->instancesMetadata; + } + + public function addInstanceMetadata(InstanceMetadata $instanceMetadata): self + { + if (!$this->instancesMetadata->contains($instanceMetadata)) { + $this->instancesMetadata->add($instanceMetadata); + $instanceMetadata->setAnrInstanceMetadataField($this); + } + + return $this; + } + + public function removeInstanceMetadata(InstanceMetadata $instanceMetadata): self + { + if ($this->instancesMetadata->contains($instanceMetadata)) { + $this->instancesMetadata->removeElement($instanceMetadata); + } + + return $this; + } + + public function getLabel(): string + { + return $this->label; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } +} diff --git a/src/Model/Entity/Asset.php b/src/Entity/Asset.php similarity index 55% rename from src/Model/Entity/Asset.php rename to src/Entity/Asset.php index 849d2103..0995a9dd 100755 --- a/src/Model/Entity/Asset.php +++ b/src/Entity/Asset.php @@ -1,21 +1,19 @@ -anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } } diff --git a/src/Entity/Client.php b/src/Entity/Client.php new file mode 100755 index 00000000..c6b1c834 --- /dev/null +++ b/src/Entity/Client.php @@ -0,0 +1,198 @@ +clientModels = new ArrayCollection(); + } + + public function getClientModels() + { + return $this->clientModels; + } + + public function addClientModel(ClientModel $clientModel): self + { + if (!$this->clientModels->contains($clientModel)) { + $this->clientModels->add($clientModel); + $clientModel->setClient($this); + } + + return $this; + } + + public function getId(): int + { + return $this->id; + } + + public function getName(): string + { + return (string)$this->name; + } + + public function setName(string $name): Client + { + $this->name = $name; + + return $this; + } + + public function getContactEmail(): string + { + return (string)$this->contactEmail; + } + + public function setContactEmail(string $contactEmail): Client + { + $this->contactEmail = $contactEmail; + + return $this; + } + + public function getLogoId(): int + { + return $this->logoId; + } + + public function setLogoId(int $logoId): self + { + $this->logoId = $logoId; + + return $this; + } + + public function getProxyAlias(): string + { + return $this->proxyAlias; + } + + public function setProxyAlias(string $proxyAlias): self + { + $this->proxyAlias = $proxyAlias; + + return $this; + } + + public function getFirstUserFirstname(): string + { + return $this->firstUserFirstname; + } + + public function setFirstUserFirstname(string $firstUserFirstname): self + { + $this->firstUserFirstname = $firstUserFirstname; + + return $this; + } + + public function getFirstUserLastname(): string + { + return $this->firstUserLastname; + } + + public function setFirstUserLastname(string $firstUserLastname): self + { + $this->firstUserLastname = $firstUserLastname; + + return $this; + } + + public function getFirstUserEmail(): string + { + return $this->firstUserEmail; + } + + public function setFirstUserEmail(string $firstUserEmail): self + { + $this->firstUserEmail = $firstUserEmail; + + return $this; + } +} diff --git a/src/Model/Entity/ClientModel.php b/src/Entity/ClientModel.php similarity index 58% rename from src/Model/Entity/ClientModel.php rename to src/Entity/ClientModel.php index c0404816..a3af0029 100644 --- a/src/Model/Entity/ClientModel.php +++ b/src/Entity/ClientModel.php @@ -1,30 +1,27 @@ -modelId; } @@ -55,6 +54,7 @@ public function getModelId(): ?int public function setModelId(int $modelId): self { $this->modelId = $modelId; + return $this; } @@ -66,6 +66,8 @@ public function getClient(): Client public function setClient(Client $client): self { $this->client = $client; + $client->addClientModel($this); + return $this; } } diff --git a/src/Model/Entity/CronTask.php b/src/Entity/CronTask.php similarity index 94% rename from src/Model/Entity/CronTask.php rename to src/Entity/CronTask.php index f3752895..67baeab0 100644 --- a/src/Model/Entity/CronTask.php +++ b/src/Entity/CronTask.php @@ -1,15 +1,15 @@ id; + } + + public function getAnr(): Anr + { + return $this->anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } + + public function getDocType(): int + { + return $this->docType; + } + + public function setDocType(int $docType): self + { + $this->docType = $docType; + + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): self + { + $this->name = $name; + + return $this; + } + + public function getVersion(): string + { + return $this->version; + } + + public function setVersion(string $version): self + { + $this->version = $version; + + return $this; + } + + public function getStatus(): int + { + return $this->status; + } + + public function setStatus(int $status): self + { + $this->status = $status; + + return $this; + } + + public function getClassification(): string + { + return $this->classification; + } + + public function setClassification(string $classification): self + { + $this->classification = $classification; + + return $this; + } + + public function getRespCustomer(): string + { + return $this->respCustomer; + } + + public function setRespCustomer(string $respCustomer): self + { + $this->respCustomer = $respCustomer; + + return $this; + } + + public function getResponsibleManager(): string + { + return $this->responsibleManager; + } + + public function setResponsibleManager(string $responsibleManager): self + { + $this->responsibleManager = $responsibleManager; + + return $this; + } + + public function getSummaryEvalRisk(): string + { + return $this->summaryEvalRisk; + } + + public function setSummaryEvalRisk(string $summaryEvalRisk): self + { + $this->summaryEvalRisk = $summaryEvalRisk; + + return $this; + } +} diff --git a/src/Model/Entity/Instance.php b/src/Entity/Instance.php similarity index 50% rename from src/Model/Entity/Instance.php rename to src/Entity/Instance.php index 2809daba..11d773d7 100755 --- a/src/Model/Entity/Instance.php +++ b/src/Entity/Instance.php @@ -1,19 +1,17 @@ -instanceMetadatas = new ArrayCollection(); + parent::__construct(); - parent::__construct($obj); + $this->instanceMetadata = new ArrayCollection(); } - /** - * @return InstanceMetadata[] - */ - public function getInstanceMetadatas() + public function getInstanceMetadata() { - return $this->instanceMetadatas; + return $this->instanceMetadata; } - public function addInstanceMetadata(InstanceMetadata $instanceMetada): self + public function addInstanceMetadata(InstanceMetadata $instanceMetadata): self { - if (!$this->instanceMetadatas->contains($instanceMetada)) { - $this->instanceMetadatas->add($instanceMetada); - $instanceMetada->setInstance($this); + if (!$this->instanceMetadata->contains($instanceMetadata)) { + $this->instanceMetadata->add($instanceMetadata); + $instanceMetadata->setInstance($this); } return $this; } + + public function getInstanceMetadataByMetadataFieldLink(AnrInstanceMetadataField $metadataField): ?InstanceMetadata + { + foreach ($this->instanceMetadata as $instanceMetadata) { + if ($this->id === $instanceMetadata->getInstance()->getId() + && $instanceMetadata->getAnrInstanceMetadataField()->getLabel() === $metadataField->getLabel() + ) { + return $instanceMetadata; + } + } + + return null; + } + + public function getHierarchyString(): string + { + return implode(' > ', array_column($this->getHierarchyArray(), 'name' . $this->anr->getLanguage())); + } } diff --git a/src/Entity/InstanceConsequence.php b/src/Entity/InstanceConsequence.php new file mode 100755 index 00000000..a968a3a4 --- /dev/null +++ b/src/Entity/InstanceConsequence.php @@ -0,0 +1,23 @@ +id; } @@ -77,30 +72,32 @@ public function getInstance(): Instance public function setInstance(Instance $instance): self { $this->instance = $instance; + $instance->addInstanceMetadata($this); return $this; } - public function getCommentTranslationKey(): string + public function getAnrInstanceMetadataField(): AnrInstanceMetadataField { - return $this->commentTranslationKey; + return $this->anrInstanceMetadataField; } - public function setCommentTranslationKey(string $commentTranslationKey): self + public function setAnrInstanceMetadataField(AnrInstanceMetadataField $anrInstanceMetadataField): self { - $this->commentTranslationKey = $commentTranslationKey; + $this->anrInstanceMetadataField = $anrInstanceMetadataField; + $anrInstanceMetadataField->addInstanceMetadata($this); return $this; } - public function getMetadata(): AnrMetadatasOnInstances + public function getComment(): string { - return $this->metadata; + return $this->comment; } - public function setMetadata(AnrMetadatasOnInstances $metadata): self + public function setComment(string $comment): self { - $this->metadata = $metadata; + $this->comment = $comment; return $this; } diff --git a/src/Entity/InstanceRisk.php b/src/Entity/InstanceRisk.php new file mode 100755 index 00000000..fa191734 --- /dev/null +++ b/src/Entity/InstanceRisk.php @@ -0,0 +1,192 @@ +recommendationRisks = new ArrayCollection(); + } + + public static function constructFromObject(InstanceRiskSuperClass $sourceInstanceRisk): InstanceRiskSuperClass + { + /** @var InstanceRisk $instanceRisk */ + $instanceRisk = parent::constructFromObject($sourceInstanceRisk); + + if ($sourceInstanceRisk instanceof self) { + $instanceRisk->setContext($sourceInstanceRisk->getContext()); + } + + return $instanceRisk; + } + + public static function constructFromObjectOfTheSameAnr(InstanceRisk $instanceRisk): static + { + return self::constructFromObject($instanceRisk) + ->setAnr($instanceRisk->getAnr()) + ->setAsset($instanceRisk->getAsset()) + ->setThreat($instanceRisk->getThreat()) + ->setVulnerability($instanceRisk->getVulnerability()) + ->setAmv($instanceRisk->getAmv()) + ->setInstanceRiskOwner($instanceRisk->getInstanceRiskOwner()); + } + + public function getRecommendationRisks() + { + return $this->recommendationRisks; + } + + + public function addRecommendationRisk(RecommendationRisk $recommendationRisk): self + { + if (!$this->recommendationRisks->contains($recommendationRisk)) { + $this->recommendationRisks->add($recommendationRisk); + } + + return $this; + } + + public function removeRecommendationRisk(RecommendationRisk $recommendationRisk): self + { + if ($this->recommendationRisks->contains($recommendationRisk)) { + $this->recommendationRisks->removeElement($recommendationRisk); + } + + return $this; + } + + public function getInstanceRiskOwner(): ?InstanceRiskOwner + { + return $this->instanceRiskOwner; + } + + public function setInstanceRiskOwner(?InstanceRiskOwner $instanceRiskOwner): self + { + if ($instanceRiskOwner === null) { + if ($this->instanceRiskOwner !== null) { + $this->instanceRiskOwner->removeInstanceRisk($this); + $this->instanceRiskOwner = null; + } + } else { + $this->instanceRiskOwner = $instanceRiskOwner; + $instanceRiskOwner->addInstanceRisk($this); + } + + return $this; + } + + public function getContext(): string + { + return (string)$this->context; + } + + public function setContext(string $context): self + { + $this->context = $context; + + return $this; + } +} diff --git a/src/Entity/InstanceRiskOp.php b/src/Entity/InstanceRiskOp.php new file mode 100755 index 00000000..e1f482ba --- /dev/null +++ b/src/Entity/InstanceRiskOp.php @@ -0,0 +1,144 @@ +recommendationRisks = new ArrayCollection(); + } + + public static function constructFromObject( + InstanceRiskOpSuperClass $sourceOperationalInstanceRisk + ): InstanceRiskOpSuperClass { + /** @var InstanceRiskOp $operationalInstanceRisk */ + $operationalInstanceRisk = parent::constructFromObject($sourceOperationalInstanceRisk); + + if ($sourceOperationalInstanceRisk instanceof self) { + $operationalInstanceRisk->setContext($sourceOperationalInstanceRisk->getContext()); + } + + return $operationalInstanceRisk; + } + + public function getRecommendationRisks() + { + return $this->recommendationRisks; + } + + public function addRecommendationRisk(RecommendationRisk $recommendationRisk): self + { + if (!$this->recommendationRisks->contains($recommendationRisk)) { + $this->recommendationRisks->add($recommendationRisk); + } + + return $this; + } + + public function removeRecommendationRisk(RecommendationRisk $recommendationRisk): self + { + if ($this->recommendationRisks->contains($recommendationRisk)) { + $this->recommendationRisks->removeElement($recommendationRisk); + } + + return $this; + } + + public function getInstanceRiskOwner(): ?InstanceRiskOwner + { + return $this->instanceRiskOwner; + } + + public function setInstanceRiskOwner(?InstanceRiskOwner $instanceRiskOwner): self + { + if ($instanceRiskOwner === null) { + if ($this->instanceRiskOwner !== null) { + $this->instanceRiskOwner->removeOperationalInstanceRisk($this); + $this->instanceRiskOwner = null; + } + } else { + $this->instanceRiskOwner = $instanceRiskOwner; + $instanceRiskOwner->addOperationalInstanceRisk($this); + } + + return $this; + } + + public function getContext(): string + { + return (string)$this->context; + } + + public function setContext(string $context): self + { + $this->context = $context; + + return $this; + } +} diff --git a/src/Entity/InstanceRiskOwner.php b/src/Entity/InstanceRiskOwner.php new file mode 100644 index 00000000..e3b26052 --- /dev/null +++ b/src/Entity/InstanceRiskOwner.php @@ -0,0 +1,152 @@ +instanceRisks = new ArrayCollection(); + $this->operationalInstanceRisks = new ArrayCollection(); + } + + public function getId() + { + return $this->id; + } + + public function getAnr(): Anr + { + return $this->anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): self + { + $this->name = $name; + + return $this; + } + + public function getInstanceRisks() + { + return $this->instanceRisks; + } + + public function addInstanceRisk(InstanceRisk $instanceRisk): self + { + if (!$this->instanceRisks->contains($instanceRisk)) { + $this->instanceRisks->add($instanceRisk); + $instanceRisk->setInstanceRiskOwner($this); + } + + return $this; + } + + public function removeInstanceRisk(InstanceRisk $instanceRisk): self + { + if ($this->instanceRisks->contains($instanceRisk)) { + $this->instanceRisks->removeElement($instanceRisk); + } + + return $this; + } + + public function getOperationalInstanceRisks() + { + return $this->operationalInstanceRisks; + } + + public function addOperationalInstanceRisk(InstanceRiskOp $operationalInstanceRisk): self + { + if (!$this->operationalInstanceRisks->contains($operationalInstanceRisk)) { + $this->operationalInstanceRisks->add($operationalInstanceRisk); + $operationalInstanceRisk->setInstanceRiskOwner($this); + } + + return $this; + } + + + public function removeOperationalInstanceRisk(InstanceRiskOp $operationalInstanceRisk): self + { + if ($this->operationalInstanceRisks->contains($operationalInstanceRisk)) { + $this->operationalInstanceRisks->removeElement($operationalInstanceRisk); + $operationalInstanceRisk->setInstanceRiskOwner(null); + } + + return $this; + } +} diff --git a/src/Model/Entity/Interview.php b/src/Entity/Interview.php similarity index 90% rename from src/Model/Entity/Interview.php rename to src/Entity/Interview.php index 2ad0a023..4e4df68a 100755 --- a/src/Model/Entity/Interview.php +++ b/src/Entity/Interview.php @@ -5,16 +5,14 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** - * Interview - * * @ORM\Table(name="interviews") * @ORM\Entity * @ORM\HasLifecycleCallbacks() @@ -34,9 +32,9 @@ class Interview extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr", cascade={"persist"}) + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=true, onDelete="CASCADE") * }) diff --git a/src/Entity/Measure.php b/src/Entity/Measure.php new file mode 100755 index 00000000..f34c7927 --- /dev/null +++ b/src/Entity/Measure.php @@ -0,0 +1,132 @@ +id; + } + + public function getAnr(): Anr + { + return $this->anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } + + public function getSoa() + { + return $this->soa; + } + + public function setSoa(Soa $soa): self + { + $this->soa = $soa; + $soa->setMeasure($this); + + return $this; + } +} diff --git a/src/Entity/MonarcObject.php b/src/Entity/MonarcObject.php new file mode 100644 index 00000000..d062f5a0 --- /dev/null +++ b/src/Entity/MonarcObject.php @@ -0,0 +1,88 @@ +anr = $anr; + $anr->addObject($this); + + return $this; + } + + public function getAnr(): Anr + { + return $this->anr; + } +} diff --git a/src/Entity/ObjectCategory.php b/src/Entity/ObjectCategory.php new file mode 100755 index 00000000..87bee7a2 --- /dev/null +++ b/src/Entity/ObjectCategory.php @@ -0,0 +1,51 @@ + $this->anr], parent::getImplicitPositionRelationsValues()); + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + $anr->addObjectCategory($this); + + return $this; + } + + public function getAnr(): Anr + { + return $this->anr; + } +} diff --git a/src/Model/Entity/ObjectObject.php b/src/Entity/ObjectObject.php similarity index 56% rename from src/Model/Entity/ObjectObject.php rename to src/Entity/ObjectObject.php index 6a68c6a8..901a1126 100755 --- a/src/Model/Entity/ObjectObject.php +++ b/src/Entity/ObjectObject.php @@ -1,18 +1,16 @@ - $this->anr, + 'parent' => [ + 'uuid' => $this->parent->getUuid(), + 'anr' => $this->anr, + ] + ]; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } + + public function getAnr(): Anr + { + return $this->anr; + } } diff --git a/src/Model/Entity/OperationalInstanceRiskScale.php b/src/Entity/OperationalInstanceRiskScale.php similarity index 76% rename from src/Model/Entity/OperationalInstanceRiskScale.php rename to src/Entity/OperationalInstanceRiskScale.php index f840dd9f..4fbffaac 100644 --- a/src/Model/Entity/OperationalInstanceRiskScale.php +++ b/src/Entity/OperationalInstanceRiskScale.php @@ -1,14 +1,14 @@ comment; + } + + public function setComment(string $comment): self + { + $this->comment = $comment; + + return $this; + } } diff --git a/src/Model/Entity/OperationalRiskScaleType.php b/src/Entity/OperationalRiskScaleType.php similarity index 52% rename from src/Model/Entity/OperationalRiskScaleType.php rename to src/Entity/OperationalRiskScaleType.php index 929817b6..8fc889fa 100644 --- a/src/Model/Entity/OperationalRiskScaleType.php +++ b/src/Entity/OperationalRiskScaleType.php @@ -1,14 +1,14 @@ label; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } } diff --git a/src/Model/Entity/PasswordToken.php b/src/Entity/PasswordToken.php similarity index 58% rename from src/Model/Entity/PasswordToken.php rename to src/Entity/PasswordToken.php index 01b0f65a..7e19eb3d 100755 --- a/src/Model/Entity/PasswordToken.php +++ b/src/Entity/PasswordToken.php @@ -1,18 +1,16 @@ -anr; } /** - * @param AnrSuperClass $anr + * @param Anr $anr */ public function setAnr($anr): self { @@ -70,13 +63,22 @@ public function getResponse() return $this->response; } - /** - * @param string $response - * @return Question - */ - public function setResponse($response) + public function setResponse(string $response): self { $this->response = $response; + + return $this; + } + + public function getMode(): int + { + return $this->mode; + } + + public function setMode(int $mode): self + { + $this->mode = $mode; + return $this; } diff --git a/src/Model/Entity/QuestionChoice.php b/src/Entity/QuestionChoice.php similarity index 71% rename from src/Model/Entity/QuestionChoice.php rename to src/Entity/QuestionChoice.php index e49cea3e..7b54b47a 100755 --- a/src/Model/Entity/QuestionChoice.php +++ b/src/Entity/QuestionChoice.php @@ -5,15 +5,12 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\AnrSuperClass; -use Monarc\Core\Model\Entity\QuestionChoiceSuperClass; +use Monarc\Core\Entity\QuestionChoiceSuperClass; /** - * Question Choice - * * @ORM\Table(name="questions_choices", indexes={ * @ORM\Index(name="question_id", columns={"question_id"}), * @ORM\Index(name="anr_id", columns={"anr_id"}), @@ -23,25 +20,22 @@ class QuestionChoice extends QuestionChoiceSuperClass { /** - * @var AnrSuperClass + * @var Anr * - * @ORM\ManyToOne(targetEntity="Anr", cascade={"persist"}) + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=true) * }) */ protected $anr; - /** - * @return AnrSuperClass - */ - public function getAnr() + public function getAnr(): Anr { return $this->anr; } /** - * @param AnrSuperClass $anr + * @param Anr $anr */ public function setAnr($anr): self { diff --git a/src/Model/Entity/Recommandation.php b/src/Entity/Recommendation.php similarity index 69% rename from src/Model/Entity/Recommandation.php rename to src/Entity/Recommendation.php index 35e6de2d..0cfcaa5d 100755 --- a/src/Model/Entity/Recommandation.php +++ b/src/Entity/Recommendation.php @@ -1,24 +1,24 @@ -recommendationRisks = new ArrayCollection(); + } - parent::__construct($obj); + public function getImplicitPositionRelationsValues(): array + { + return ['anr' => $this->anr]; } - public function getUuid(): ?string + public function getUuid(): string { - return $this->uuid; + return (string)$this->uuid; } public function setUuid($uuid): self @@ -185,15 +179,12 @@ public function generateAndSetUuid(): self return $this; } - /** - * @return Anr - */ - public function getAnr() + public function getAnr(): Anr { return $this->anr; } - public function setAnr($anr): self + public function setAnr(Anr $anr): self { $this->anr = $anr; @@ -202,30 +193,32 @@ public function setAnr($anr): self public function getDueDate(): ?DateTime { - return $this->duedate; + return $this->dueDate; } public function setDueDate(?DateTime $date): self { - $this->duedate = $date; + $this->dueDate = $date; return $this; } - /** - * @return RecommandationSet - */ - public function getRecommandationSet() + public function setDueDateFromString(string $dateString): self { - return $this->recommandationSet; + $this->dueDate = new DateTime($dateString); + + return $this; } - /** - * @param RecommandationSet $recommandationSet - */ - public function setRecommandationSet($recommandationSet): self + public function getRecommendationSet(): RecommendationSet + { + return $this->recommendationSet; + } + + public function setRecommendationSet(RecommendationSet $recommendationSet): self { - $this->recommandationSet = $recommandationSet; + $this->recommendationSet = $recommendationSet; + $recommendationSet->addRecommendation($this); return $this; } @@ -240,9 +233,19 @@ public function getRecommendationRisks() return $this->recommendationRisks; } + public function addRecommendationRisk(RecommendationRisk $recommendationRisk): self + { + if (!$this->recommendationRisks->contains($recommendationRisk)) { + $this->recommendationRisks->add($recommendationRisk); + $recommendationRisk->setRecommendation($this); + } + + return $this; + } + public function hasLinkedRecommendationRisks(): bool { - return $this->recommendationRisks !== null && !$this->recommendationRisks->isEmpty(); + return !$this->recommendationRisks->isEmpty(); } public function setPosition(int $position): self @@ -276,6 +279,16 @@ public function isImportanceEmpty(): bool return $this->importance === static::EMPTY_IMPORTANCE; } + public static function getImportances(): array + { + return [ + static::EMPTY_IMPORTANCE => 'not set', + static::LOW_IMPORTANCE => 'low', + static::MEDIUM_IMPORTANCE => 'medium', + static::HIGH_IMPORTANCE => 'high', + ]; + } + public function isPositionEmpty(): bool { return $this->position === static::EMPTY_POSITION; @@ -349,7 +362,7 @@ public function getComment(): string return (string)$this->comment; } - public function setComment(string $comment): Recommandation + public function setComment(string $comment): Recommendation { $this->comment = $comment; @@ -368,14 +381,14 @@ public function setStatus(int $status): self return $this; } - public function getResponsable(): string + public function getResponsible(): string { - return (string)$this->responsable; + return (string)$this->responsible; } - public function setResponsable(string $responsable): Recommandation + public function setResponsible(string $responsible): Recommendation { - $this->responsable = $responsable; + $this->responsible = $responsible; return $this; } @@ -398,27 +411,4 @@ public function incrementCounterTreated(): self return $this; } - - public function getFiltersForService() - { - $filterJoin = [ - [ - 'as' => 'r', - 'rel' => 'recommandationSet', - ], - ]; - $filterLeft = [ - [ - 'as' => 'r1', - 'rel' => 'recommandationSet', - ], - ]; - $filtersCol = [ - 'r.uuid', - 'r.anr', - 'r.code', - ]; - - return [$filterJoin, $filterLeft, $filtersCol]; - } } diff --git a/src/Entity/RecommendationHistory.php b/src/Entity/RecommendationHistory.php new file mode 100755 index 00000000..b0d153ce --- /dev/null +++ b/src/Entity/RecommendationHistory.php @@ -0,0 +1,629 @@ +setIsFinal($recommendationHistory->isFinal()) + ->setImplComment($recommendationHistory->getImplComment()) + ->setRecoCode($recommendationHistory->getRecoCode()) + ->setRecoDescription($recommendationHistory->getRecoDescription()) + ->setRecoImportance($recommendationHistory->getRecoImportance()) + ->setRecoComment($recommendationHistory->getRecoComment()) + ->setRecoResponsable($recommendationHistory->getRecoResponsable()) + ->setRecoDueDate($recommendationHistory->getRecoDueDate()) + ->setRiskInstance($recommendationHistory->getRiskInstance()) + ->setRiskInstanceContext($recommendationHistory->getRiskInstanceContext()) + ->setRiskAsset($recommendationHistory->getRiskAsset()) + ->setRiskThreat($recommendationHistory->getRiskThreat()) + ->setRiskThreatVal($recommendationHistory->getRiskThreatVal()) + ->setRiskVul($recommendationHistory->getRiskVul()) + ->setRiskVulValBefore($recommendationHistory->getRiskVulValBefore()) + ->setRiskVulValAfter($recommendationHistory->getRiskVulValAfter()) + ->setRiskKindOfMeasure($recommendationHistory->getRiskKindOfMeasure()) + ->setRiskColorBefore($recommendationHistory->getRiskColorBefore()) + ->setRiskColorAfter($recommendationHistory->getRiskColorAfter()) + ->setCacheCommentAfter($recommendationHistory->getCacheCommentAfter()) + ->setNetProbBefore($recommendationHistory->getNetProbBefore()) + ->setRiskOpDescription($recommendationHistory->getRiskOpDescription()) + ->setRiskCommentBefore($recommendationHistory->getRiskCommentBefore()) + ->setRiskCommentAfter($recommendationHistory->getRiskCommentAfter()) + ->setRiskMaxRiskBefore($recommendationHistory->getRiskMaxRiskBefore()) + ->setRiskMaxRiskAfter($recommendationHistory->getRiskMaxRiskAfter()); + } + + public function getId(): int + { + return $this->id; + } + + public function getAnr(): Anr + { + return $this->anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } + + public function getInstanceRisk(): ?InstanceRisk + { + return $this->instanceRisk; + } + + public function setInstanceRisk(InstanceRisk $instanceRisk): self + { + $this->instanceRisk = $instanceRisk; + + return $this; + } + + public function getInstanceRiskOp(): ?InstanceRiskOp + { + return $this->instanceRiskOp; + } + + public function setInstanceRiskOp(InstanceRiskOp $instanceRiskOp): self + { + $this->instanceRiskOp = $instanceRiskOp; + + return $this; + } + + public function isFinal(): bool + { + return (bool)$this->isFinal; + } + + public function setIsFinal(bool $isFinal): self + { + $this->isFinal = (int)$isFinal; + + return $this; + } + + public function getImplComment(): string + { + return (string)$this->implComment; + } + + public function setImplComment(string $implComment): self + { + $this->implComment = $implComment; + + return $this; + } + + public function getRecoCode(): string + { + return (string)$this->recoCode; + } + + public function setRecoCode(string $recoCode): self + { + $this->recoCode = $recoCode; + + return $this; + } + + public function getRecoDescription(): string + { + return (string)$this->recoDescription; + } + + public function setRecoDescription(string $recoDescription): self + { + $this->recoDescription = $recoDescription; + + return $this; + } + + public function getRecoImportance(): int + { + return $this->recoImportance; + } + + public function setRecoImportance(int $recoImportance): self + { + $this->recoImportance = $recoImportance; + + return $this; + } + + public function getRecoComment(): string + { + return (string)$this->recoComment; + } + + public function setRecoComment(string $recoComment): self + { + $this->recoComment = $recoComment; + + return $this; + } + + public function getRecoResponsable(): string + { + return (string)$this->recoResponsable; + } + + public function setRecoResponsable(string $recoResponsable): self + { + $this->recoResponsable = $recoResponsable; + + return $this; + } + + public function getRecoDueDate(): ?DateTime + { + return $this->recoDueDate; + } + + public function setRecoDueDate(?DateTime $recoDueDate): self + { + $this->recoDueDate = $recoDueDate; + + return $this; + } + + public function getRiskInstance(): string + { + return (string)$this->riskInstance; + } + + public function setRiskInstance(string $riskInstance): self + { + $this->riskInstance = $riskInstance; + + return $this; + } + + public function getRiskInstanceContext(): string + { + return (string)$this->riskInstanceContext; + } + + public function setRiskInstanceContext(string $riskInstanceContext): self + { + $this->riskInstanceContext = $riskInstanceContext; + + return $this; + } + + public function getRiskAsset(): string + { + return (string)$this->riskAsset; + } + + public function setRiskAsset(string $riskAsset): self + { + $this->riskAsset = $riskAsset; + + return $this; + } + + public function getRiskThreat(): string + { + return (string)$this->riskThreat; + } + + public function setRiskThreat(string $riskThreat): self + { + $this->riskThreat = $riskThreat; + + return $this; + } + + public function getRiskThreatVal(): int + { + return $this->riskThreatVal; + } + + public function setRiskThreatVal(int $riskThreatVal): self + { + $this->riskThreatVal = $riskThreatVal; + + return $this; + } + + public function getRiskVul(): string + { + return (string)$this->riskVul; + } + + public function setRiskVul(string $riskVul): self + { + $this->riskVul = $riskVul; + + return $this; + } + + public function getRiskVulValBefore(): int + { + return $this->riskVulValBefore; + } + + public function setRiskVulValBefore(int $riskVulValBefore): self + { + $this->riskVulValBefore = $riskVulValBefore; + + return $this; + } + + public function getRiskVulValAfter(): int + { + return $this->riskVulValAfter; + } + + public function setRiskVulValAfter(int $riskVulValAfter): self + { + $this->riskVulValAfter = $riskVulValAfter; + + return $this; + } + + public function getRiskOpDescription(): string + { + return (string)$this->riskOpDescription; + } + + public function setRiskOpDescription(string $riskOpDescription): self + { + $this->riskOpDescription = $riskOpDescription; + + return $this; + } + + public function getNetProbBefore(): int + { + return $this->netProbBefore; + } + + public function setNetProbBefore(int $netProbBefore): self + { + $this->netProbBefore = $netProbBefore; + + return $this; + } + + public function getRiskKindOfMeasure(): int + { + return $this->riskKindOfMeasure; + } + + public function setRiskKindOfMeasure(int $riskKindOfMeasure): self + { + $this->riskKindOfMeasure = $riskKindOfMeasure; + + return $this; + } + + public function getRiskCommentBefore(): string + { + return (string)$this->riskCommentBefore; + } + + public function setRiskCommentBefore(string $riskCommentBefore): self + { + $this->riskCommentBefore = $riskCommentBefore; + + return $this; + } + + public function getRiskCommentAfter(): string + { + return (string)$this->riskCommentAfter; + } + + public function setRiskCommentAfter(string $riskCommentAfter): self + { + $this->riskCommentAfter = $riskCommentAfter; + + return $this; + } + + public function getRiskMaxRiskBefore(): int + { + return $this->riskMaxRiskBefore; + } + + public function setRiskMaxRiskBefore(int $riskMaxRiskBefore): self + { + $this->riskMaxRiskBefore = $riskMaxRiskBefore; + + return $this; + } + + public function getRiskColorBefore(): string + { + return (string)$this->riskColorBefore; + } + + public function setRiskColorBefore(string $riskColorBefore): self + { + $this->riskColorBefore = $riskColorBefore; + + return $this; + } + + public function getRiskMaxRiskAfter(): int + { + return $this->riskMaxRiskAfter; + } + + public function setRiskMaxRiskAfter(int $riskMaxRiskAfter): self + { + $this->riskMaxRiskAfter = $riskMaxRiskAfter; + + return $this; + } + + public function getRiskColorAfter(): string + { + return (string)$this->riskColorAfter; + } + + public function setRiskColorAfter(string $riskColorAfter): self + { + $this->riskColorAfter = $riskColorAfter; + + return $this; + } + + public function getCacheCommentAfter(): string + { + return (string)$this->cacheCommentAfter; + } + + public function setCacheCommentAfter(string $cacheCommentAfter): self + { + $this->cacheCommentAfter = $cacheCommentAfter; + + return $this; + } +} diff --git a/src/Model/Entity/RecommandationRisk.php b/src/Entity/RecommendationRisk.php similarity index 54% rename from src/Model/Entity/RecommandationRisk.php rename to src/Entity/RecommendationRisk.php index f01b5efe..05f24608 100755 --- a/src/Model/Entity/RecommandationRisk.php +++ b/src/Entity/RecommendationRisk.php @@ -1,31 +1,28 @@ -id; - } + protected $commentAfter = ''; - /** - * @param int $id - */ - public function setId($id): self + public function getId(): int { - $this->id = $id; - - return $this; + return $this->id; } - // TODO: the nullable value is added for the multi-fields relation issue (when we remove a relation, e.g. asset). - // TODO: remove when #240 is done. - public function getAnr(): ?Anr + public function getAnr(): Anr { return $this->anr; } - public function setAnr(?Anr $anr): self + public function setAnr(Anr $anr): self { $this->anr = $anr; return $this; } - public function getRecommandation(): ?Recommandation + public function getRecommendation(): Recommendation { - return $this->recommandation; + return $this->recommendation; } - public function setRecommandation(?Recommandation $recommandation): self + public function setRecommendation(Recommendation $recommendation): self { - $this->recommandation = $recommandation; + $this->recommendation = $recommendation; + $recommendation->addRecommendationRisk($this); return $this; } @@ -186,7 +172,15 @@ public function getInstanceRisk(): ?InstanceRisk public function setInstanceRisk(?InstanceRisk $instanceRisk): self { - $this->instanceRisk = $instanceRisk; + if ($instanceRisk === null) { + if ($this->instanceRisk !== null) { + $this->instanceRisk->removeRecommendationRisk($this); + $this->instanceRisk = null; + } + } else { + $this->instanceRisk = $instanceRisk; + $instanceRisk->addRecommendationRisk($this); + } return $this; } @@ -198,17 +192,25 @@ public function getInstanceRiskOp(): ?InstanceRiskOp public function setInstanceRiskOp(?InstanceRiskOp $instanceRiskOp) { - $this->instanceRiskOp = $instanceRiskOp; + if ($instanceRiskOp === null) { + if ($this->instanceRiskOp !== null) { + $this->instanceRiskOp->removeRecommendationRisk($this); + $this->instanceRiskOp = null; + } + } else { + $this->instanceRiskOp = $instanceRiskOp; + $instanceRiskOp->addRecommendationRisk($this); + } return $this; } - public function getInstance(): ?Instance + public function getInstance(): Instance { return $this->instance; } - public function setInstance(?Instance $instance): self + public function setInstance(Instance $instance): self { $this->instance = $instance; @@ -279,75 +281,4 @@ public function setCommentAfter(string $commentAfter): self return $this; } - - /** - * @param bool $partial - * - * @return mixed - */ - public function getInputFilter($partial = true) - { - if (!$this->inputFilter) { - parent::getInputFilter($partial); - - $this->inputFilter->add([ - 'name' => 'anr', - 'required' => !$partial, - 'allow_empty' => false, - ]); - - $this->inputFilter->add([ - 'name' => 'recommandation', - 'required' => !$partial, - 'allow_empty' => false, - ]); - - $this->inputFilter->add([ - 'name' => 'risk', - 'required' => !$partial, - 'allow_empty' => false, - ]); - - $this->inputFilter->add([ - 'name' => 'op', - 'required' => !$partial, - 'allow_empty' => false, - 'validators' => [ - [ - 'name' => 'InArray', - 'options' => [ - 'haystack' => [0, 1], - ], - 'default' => 0, - ], - ], - ]); - } - - return $this->inputFilter; - } - - public function getFiltersForService() - { - $filterJoin = [ - [ - 'as' => 'r', - 'rel' => 'recommandation', - ], - ]; - $filterLeft = [ - [ - 'as' => 'r1', - 'rel' => 'recommandation', - ], - - ]; - $filtersCol = [ - 'r.uuid', - 'r.anr', - 'r.code', - ]; - - return [$filterJoin, $filterLeft, $filtersCol]; - } } diff --git a/src/Entity/RecommendationSet.php b/src/Entity/RecommendationSet.php new file mode 100644 index 00000000..7862eb05 --- /dev/null +++ b/src/Entity/RecommendationSet.php @@ -0,0 +1,136 @@ +recommendations = new ArrayCollection(); + } + + public function getUuid(): string + { + return (string)$this->uuid; + } + + /** + * @param string $uuid + * @return self + */ + public function setUuid($uuid): self + { + $this->uuid = $uuid; + + return $this; + } + + /** + * @ORM\PrePersist + */ + public function generateAndSetUuid(): self + { + if ($this->uuid === null) { + $this->uuid = Uuid::uuid4(); + } + + return $this; + } + + public function getAnr(): Anr + { + return $this->anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + $anr->addRecommendationSet($this); + + return $this; + } + + public function getRecommendations() + { + return $this->recommendations; + } + + public function addRecommendation(Recommendation $recommendation): self + { + if (!$this->recommendations->contains($recommendation)) { + $this->recommendations->add($recommendation); + $recommendation->setRecommendationSet($this); + } + + return $this; + } + + public function setLabel(string $label): self + { + $this->label = $label; + + return $this; + } + + public function getLabel(): string + { + return $this->label; + } +} diff --git a/src/Model/Entity/Record.php b/src/Entity/Record.php similarity index 91% rename from src/Model/Entity/Record.php rename to src/Entity/Record.php index 6b452132..66ad50a7 100644 --- a/src/Model/Entity/Record.php +++ b/src/Entity/Record.php @@ -5,14 +5,14 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; use Doctrine\Common\Collections\Collection; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * Record @@ -40,7 +40,7 @@ class Record extends AbstractEntity /** * @var Anr * - * @ORM\ManyToOne(targetEntity="Anr", cascade={"persist"}) + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -55,7 +55,7 @@ class Record extends AbstractEntity protected $label; /** - * @var array + * @var string * * @ORM\Column(name="purposes", type="text", nullable=true) */ @@ -91,7 +91,7 @@ class Record extends AbstractEntity /** * @var Collection|RecordActor[] - * @ORM\ManyToMany(targetEntity="Monarc\FrontOffice\Model\Entity\RecordActor", cascade={"persist"}) + * @ORM\ManyToMany(targetEntity="RecordActor", cascade={"persist"}) * @ORM\JoinTable(name="records_record_joint_controllers", * joinColumns={@ORM\JoinColumn(name="record_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="controller_id", referencedColumnName="id")} @@ -187,20 +187,32 @@ public function setlabel($label) $this->label = $label; } - /** - * @return array - */ - public function getPurposes() + public function getlabel(): string { - return $this->purposes; + return (string)$this->label; } - /** - * @param string $purposes - * @return Record - */ - public function setPurposes($purposes) + + public function getPurposes(): string + { + return (string)$this->purposes; + } + + public function setPurposes(string $purposes) { $this->purposes = $purposes; + + return $this; + } + + public function getSecMeasures(): string + { + return (string)$this->secMeasures; + } + + public function setSecMeasures(string $secMeasures): self + { + $this->secMeasures = $secMeasures; + return $this; } diff --git a/src/Model/Entity/RecordActor.php b/src/Entity/RecordActor.php similarity index 82% rename from src/Model/Entity/RecordActor.php rename to src/Entity/RecordActor.php index 9933c6fd..66530d5d 100644 --- a/src/Model/Entity/RecordActor.php +++ b/src/Entity/RecordActor.php @@ -5,12 +5,12 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * RecordActor @@ -36,9 +36,9 @@ class RecordActor extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr") + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -53,7 +53,7 @@ class RecordActor extends AbstractEntity protected $label; /** - * @var array + * @var string * * @ORM\Column(name="contact", type="string", length=255, nullable=true) */ @@ -109,4 +109,14 @@ public function setContact($contact) $this->contact = $contact; return $this; } + + public function getLabel(): string + { + return (string)$this->label; + } + + public function getContact(): string + { + return (string)$this->contact; + } } diff --git a/src/Model/Entity/RecordDataCategory.php b/src/Entity/RecordDataCategory.php similarity index 83% rename from src/Model/Entity/RecordDataCategory.php rename to src/Entity/RecordDataCategory.php index 0fd63139..8353232e 100644 --- a/src/Model/Entity/RecordDataCategory.php +++ b/src/Entity/RecordDataCategory.php @@ -5,12 +5,12 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * RecordDataCategory @@ -36,9 +36,9 @@ class RecordDataCategory extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr") + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) diff --git a/src/Model/Entity/RecordInternationalTransfer.php b/src/Entity/RecordInternationalTransfer.php similarity index 85% rename from src/Model/Entity/RecordInternationalTransfer.php rename to src/Entity/RecordInternationalTransfer.php index 148049a1..b8568cb4 100644 --- a/src/Model/Entity/RecordInternationalTransfer.php +++ b/src/Entity/RecordInternationalTransfer.php @@ -5,12 +5,12 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * RecordInternationalTransfer @@ -36,9 +36,9 @@ class RecordInternationalTransfer extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr") + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -46,8 +46,8 @@ class RecordInternationalTransfer extends AbstractEntity protected $anr; /** - * @var \Monarc\FrontOffice\Model\Entity\Record - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Record") + * @var Record + * @ORM\ManyToOne(targetEntity="Record") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="record_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) diff --git a/src/Model/Entity/RecordPersonalData.php b/src/Entity/RecordPersonalData.php similarity index 87% rename from src/Model/Entity/RecordPersonalData.php rename to src/Entity/RecordPersonalData.php index 5a938af4..cae9167d 100644 --- a/src/Model/Entity/RecordPersonalData.php +++ b/src/Entity/RecordPersonalData.php @@ -5,13 +5,14 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Doctrine\Common\Collections\Collection; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * RecordPersonalData @@ -38,9 +39,9 @@ class RecordPersonalData extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr") + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -48,8 +49,8 @@ class RecordPersonalData extends AbstractEntity protected $anr; /** - * @var \Monarc\FrontOffice\Model\Entity\Record - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Record") + * @var Record + * @ORM\ManyToOne(targetEntity="Record") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="record_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -64,8 +65,8 @@ class RecordPersonalData extends AbstractEntity protected $dataSubject; /** - * @var \Doctrine\Common\Collections\Collection - * @ORM\ManyToMany(targetEntity="Monarc\FrontOffice\Model\Entity\RecordDataCategory", cascade={"persist"}) + * @var Collection + * @ORM\ManyToMany(targetEntity="RecordDataCategory", cascade={"persist"}) * @ORM\JoinTable(name="record_personal_data_record_data_categories", * joinColumns={@ORM\JoinColumn(name="personal_data_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="data_category_id", referencedColumnName="id")} diff --git a/src/Model/Entity/RecordProcessor.php b/src/Entity/RecordProcessor.php similarity index 84% rename from src/Model/Entity/RecordProcessor.php rename to src/Entity/RecordProcessor.php index f5b3178f..c09d7528 100644 --- a/src/Model/Entity/RecordProcessor.php +++ b/src/Entity/RecordProcessor.php @@ -5,12 +5,12 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * RecordProcessor @@ -36,9 +36,9 @@ class RecordProcessor extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr") + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -75,15 +75,15 @@ class RecordProcessor extends AbstractEntity protected $secMeasures; /** - * @var \Monarc\FrontOffice\Model\Entity\RecordActor - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\RecordActor", cascade={"persist"}) + * @var RecordActor + * @ORM\ManyToOne(targetEntity="RecordActor", cascade={"persist"}) * @ORM\JoinColumn(name="representative", referencedColumnName="id", nullable=true, onDelete="SET NULL") */ protected $representative; /** - * @var \Monarc\FrontOffice\Model\Entity\RecordActor - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\RecordActor", cascade={"persist"}) + * @var RecordActor + * @ORM\ManyToOne(targetEntity="RecordActor", cascade={"persist"}) * @ORM\JoinColumn(name="dpo", referencedColumnName="id", nullable=true, onDelete="SET NULL") */ protected $dpo; diff --git a/src/Model/Entity/RecordRecipient.php b/src/Entity/RecordRecipient.php similarity index 82% rename from src/Model/Entity/RecordRecipient.php rename to src/Entity/RecordRecipient.php index 939d740c..905a9464 100644 --- a/src/Model/Entity/RecordRecipient.php +++ b/src/Entity/RecordRecipient.php @@ -5,12 +5,12 @@ * @license MONARC is licensed under GNU Affero General Public License version 3 */ -namespace Monarc\FrontOffice\Model\Entity; +namespace Monarc\FrontOffice\Entity; -use Monarc\Core\Model\Entity\AbstractEntity; +use Monarc\Core\Entity\AbstractEntity; use Doctrine\ORM\Mapping as ORM; -use Monarc\Core\Model\Entity\Traits\CreateEntityTrait; -use Monarc\Core\Model\Entity\Traits\UpdateEntityTrait; +use Monarc\Core\Entity\Traits\CreateEntityTrait; +use Monarc\Core\Entity\Traits\UpdateEntityTrait; /** * RecordRecipient @@ -36,9 +36,9 @@ class RecordRecipient extends AbstractEntity protected $id; /** - * @var \Monarc\FrontOffice\Model\Entity\Anr + * @var Anr * - * @ORM\ManyToOne(targetEntity="Monarc\FrontOffice\Model\Entity\Anr") + * @ORM\ManyToOne(targetEntity="Anr") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="anr_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * }) @@ -53,11 +53,12 @@ class RecordRecipient extends AbstractEntity protected $label; /** + * 0 for internal recipients and 1 for external recipients. + * * @var bool * * @ORM\Column(name="type", type="string", length=255, nullable=true) */ - // 0 for internal recipients and 1 for external recipients protected $type; /** @@ -102,4 +103,9 @@ public function setAnr($anr): self return $this; } + + public function getType(): int + { + return (int)$this->type; + } } diff --git a/src/Entity/Referential.php b/src/Entity/Referential.php new file mode 100644 index 00000000..298722ac --- /dev/null +++ b/src/Entity/Referential.php @@ -0,0 +1,49 @@ +anr = $anr; + $anr->addReferential($this); + + return $this; + } + + public function getAnr(): Anr + { + return $this->anr; + } +} diff --git a/src/Entity/RolfRisk.php b/src/Entity/RolfRisk.php new file mode 100755 index 00000000..93b04655 --- /dev/null +++ b/src/Entity/RolfRisk.php @@ -0,0 +1,55 @@ +anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } +} diff --git a/src/Model/Entity/Referential.php b/src/Entity/RolfTag.php old mode 100644 new mode 100755 similarity index 54% rename from src/Model/Entity/Referential.php rename to src/Entity/RolfTag.php index 54290eaf..bca3340c --- a/src/Model/Entity/Referential.php +++ b/src/Entity/RolfTag.php @@ -1,29 +1,27 @@ -anr; + } + + public function setAnr(Anr $anr): self { $this->anr = $anr; diff --git a/src/Entity/Scale.php b/src/Entity/Scale.php new file mode 100755 index 00000000..b0cc3d35 --- /dev/null +++ b/src/Entity/Scale.php @@ -0,0 +1,24 @@ +type]['min'], $data[$this->type]['max']) + && ($data[$this->type]['min'] !== $this->min || $data[$this->type]['max'] !== $this->max); + } +} diff --git a/src/Model/Entity/ScaleComment.php b/src/Entity/ScaleComment.php similarity index 70% rename from src/Model/Entity/ScaleComment.php rename to src/Entity/ScaleComment.php index 4976bce3..429b1d2f 100755 --- a/src/Model/Entity/ScaleComment.php +++ b/src/Entity/ScaleComment.php @@ -1,18 +1,16 @@ -id; } - public function setId(int $id): self - { - $this->id = $id; - - return $this; - } - public function getAnr(): Anr { return $this->anr; } - /** - * @param Anr $anr - * - * @return Snapshot - */ public function setAnr(Anr $anr): self { $this->anr = $anr; @@ -91,21 +78,22 @@ public function setAnr(Anr $anr): self return $this; } - public function getAnrReference(): ?Anr + public function getAnrReference(): Anr { return $this->anrReference; } - public function setAnrReference($anrReference): self + public function setAnrReference(Anr $anrReference): self { $this->anrReference = $anrReference; + $anrReference->addReferencedSnapshot($this); return $this; } - public function getComment(): ?string + public function getComment(): string { - return $this->comment; + return (string)$this->comment; } public function setComment(?string $comment): self diff --git a/src/Model/Entity/Soa.php b/src/Entity/Soa.php similarity index 53% rename from src/Model/Entity/Soa.php rename to src/Entity/Soa.php index eb7bd574..5083eaa7 100755 --- a/src/Model/Entity/Soa.php +++ b/src/Entity/Soa.php @@ -1,28 +1,25 @@ - 'm', - 'rel' => 'measure', - ], - ]; - $filterLeft = [ - ]; - $filtersCol = [ - 'm.label1', - 'm.label2', - 'm.label3', - 'm.label4', - 'm.code', - 'remarks', - 'actions', - 'evidences' - ]; - - return [$filterJoin, $filterLeft, $filtersCol]; - } - - /** - * @return int - */ public function getId() { return $this->id; } - /** - * @param int $id - */ - public function setId($id) - { - $this->id = $id; - } - - /** - * @return Measure - */ - public function getMeasure() + public function getMeasure(): Measure { return $this->measure; } - /** - * @param Measure $measure - * - */ - public function setMeasure($measure): self + public function setMeasure(Measure $measure): self { $this->measure = $measure; return $this; } - /** - * @return Anr - */ - public function getAnr() + public function getAnr(): Anr { return $this->anr; } - /** - * @param Anr $anr - * - * @return Soa - */ - public function setAnr($anr) + public function setAnr(Anr $anr): self { $this->anr = $anr; return $this; } - /** - * @return string - */ - public function getRemarks() + public function getRemarks(): string { - return $this->remarks; + return (string)$this->remarks; } - /** - * @param string $remarks - */ - public function setRemarks($remarks): self + public function setRemarks(string $remarks): self { $this->remarks = $remarks; return $this; } - /** - * @return string - */ - public function getEvidences() + public function getEvidences(): string { - return $this->evidences; + return (string)$this->evidences; } - /** - * @param string $evidences - */ - public function setEvidences($evidences): self + public function setEvidences(string $evidences): self { $this->evidences = $evidences; return $this; } - /** - * @return string - */ - public function getActions() + public function getActions(): string { - return $this->actions; + return (string)$this->actions; } - /** - * @param string $actions - */ - public function setActions($actions): self + public function setActions(string $actions): self { $this->actions = $actions; return $this; } - /** - * @return integer - */ public function getCompliance() { return $this->compliance; } - /** - * @param integer $compliance - */ - public function setCompliance($compliance): self + public function setCompliance(int $compliance): self { $this->compliance = $compliance; return $this; } - /** - * @return int - */ - public function getEx() + public function getEx(): int { return $this->EX; } - /** - * @param int $EX - */ - public function setEx($EX): self + public function setEx(int $EX): self { $this->EX = $EX; return $this; } - /** - * @return int - */ - public function getLr() + public function getLr(): int { return $this->LR; } - /** - * @param int $LR - */ - public function setLr($LR): self + public function setLr(int $LR): self { $this->LR = $LR; return $this; } - /** - * @return int - */ - public function getCo() + public function getCo(): int { return $this->CO; } - /** - * @param int $CO - */ - public function setCo($CO): self + public function setCo(int $CO): self { $this->CO = $CO; return $this; } - /** - * @return int - */ - public function getBr() + public function getBr(): int { return $this->BR; } - /** - * @param int $BR - */ - public function setBr($BR): self + public function setBr(int $BR): self { $this->BR = $BR; return $this; } - /** - * @return int - */ - public function getBp() + public function getBp(): int { return $this->BP; } - /** - * @param int $BP - */ - public function setBp($BP): self + public function setBp(int $BP): self { $this->BP = $BP; return $this; } - /** - * @return int - */ - public function getRra() + public function getRra(): int { return $this->RRA; } - /** - * @param int $RRA - */ - public function setRra($RRA): self + public function setRra(int $RRA): self { $this->RRA = $RRA; return $this; } - /** - * @return SoaScaleComment - */ public function getSoaScaleComment(): ?SoaScaleComment { return $this->soaScaleComment; } - /** - * @param SoaScaleComment $RRA - */ - public function setSoaScaleComment($soaScaleComment): self + public function setSoaScaleComment(SoaScaleComment $soaScaleComment): self { $this->soaScaleComment = $soaScaleComment; + $soaScaleComment->addSoa($this); return $this; } diff --git a/src/Model/Entity/SoaCategory.php b/src/Entity/SoaCategory.php similarity index 54% rename from src/Model/Entity/SoaCategory.php rename to src/Entity/SoaCategory.php index 2129cfcb..6629e535 100755 --- a/src/Model/Entity/SoaCategory.php +++ b/src/Entity/SoaCategory.php @@ -1,18 +1,16 @@ -anr; } - /** - * @param Anr $anr - */ - public function setAnr($anr): self + public function setAnr(Anr $anr): self { $this->anr = $anr; diff --git a/src/Entity/SoaScaleComment.php b/src/Entity/SoaScaleComment.php new file mode 100644 index 00000000..1f252074 --- /dev/null +++ b/src/Entity/SoaScaleComment.php @@ -0,0 +1,67 @@ +soas = new ArrayCollection(); + } + + public function getComment(): string + { + return (string)$this->comment; + } + + public function setComment(string $comment): self + { + $this->comment = $comment; + + return $this; + } + + public function getSoas() + { + return $this->soas; + } + + public function addSoa(Soa $soa): self + { + if (!$this->soas->contains($soa)) { + $this->soas->add($soa); + $soa->setSoaScaleComment($this); + } + + return $this; + } +} diff --git a/src/Entity/SystemMessage.php b/src/Entity/SystemMessage.php new file mode 100755 index 00000000..284e7c2a --- /dev/null +++ b/src/Entity/SystemMessage.php @@ -0,0 +1,115 @@ +id; + } + + public function getUser(): User + { + return $this->user; + } + + public function setUser(User $user): self + { + $this->user = $user; + + return $this; + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): self + { + $this->title = $title; + + return $this; + } + + public function getDescription(): string + { + return (string)$this->description; + } + + public function setDescription(string $description): self + { + $this->description = $description; + + return $this; + } + + public function getStatus(): int + { + return $this->status; + } + + public function setStatus(int $status): self + { + $this->status = $status; + + return $this; + } +} diff --git a/src/Entity/Theme.php b/src/Entity/Theme.php new file mode 100755 index 00000000..5276d27f --- /dev/null +++ b/src/Entity/Theme.php @@ -0,0 +1,42 @@ +anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } +} diff --git a/src/Model/Entity/Threat.php b/src/Entity/Threat.php similarity index 61% rename from src/Model/Entity/Threat.php rename to src/Entity/Threat.php index c7205d9f..233650ee 100755 --- a/src/Model/Entity/Threat.php +++ b/src/Entity/Threat.php @@ -1,19 +1,17 @@ -anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } } diff --git a/src/Model/Entity/User.php b/src/Entity/User.php similarity index 76% rename from src/Model/Entity/User.php rename to src/Entity/User.php index c3180e3c..b359637a 100755 --- a/src/Model/Entity/User.php +++ b/src/Entity/User.php @@ -1,21 +1,18 @@ -userAnrs; } @@ -76,9 +70,10 @@ public function getUserAnrs(): Collection */ public function setUserAnrs(array $userAnrs): self { - $this->userAnrs = new ArrayCollection(); foreach ($userAnrs as $userAnr) { - $this->addUserAnr($userAnr); + if ($userAnr instanceof UserAnr) { + $this->addUserAnr($userAnr); + } } return $this; @@ -86,8 +81,10 @@ public function setUserAnrs(array $userAnrs): self public function addUserAnr(UserAnr $userAnr): self { - $this->userAnrs->add($userAnr); - $userAnr->setUser($this); + if (!$this->userAnrs->contains($userAnr)) { + $this->userAnrs->add($userAnr); + $userAnr->setUser($this); + } return $this; } diff --git a/src/Entity/UserAnr.php b/src/Entity/UserAnr.php new file mode 100755 index 00000000..4cce32ee --- /dev/null +++ b/src/Entity/UserAnr.php @@ -0,0 +1,106 @@ +id; + } + + public function getUser(): User + { + return $this->user; + } + + public function setUser(User $user): self + { + $this->user = $user; + $user->addUserAnr($this); + + return $this; + } + + public function getAnr(): Anr + { + return $this->anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + $anr->addUserAnrPermission($this); + + return $this; + } + + public function getRwd(): int + { + return $this->rwd; + } + + public function setRwd(int $rwd): self + { + $this->rwd = $rwd; + + return $this; + } + + public function hasWriteAccess(): bool + { + return $this->rwd === self::FULL_PERMISSIONS_RWD; + } +} diff --git a/src/Entity/UserRole.php b/src/Entity/UserRole.php new file mode 100644 index 00000000..fc425fc4 --- /dev/null +++ b/src/Entity/UserRole.php @@ -0,0 +1,28 @@ +anr; + } + + public function setAnr(Anr $anr): self + { + $this->anr = $anr; + + return $this; + } } diff --git a/src/Exception/UserNotAuthorizedException.php b/src/Exception/UserNotAuthorizedException.php deleted file mode 100644 index da2c77f2..00000000 --- a/src/Exception/UserNotAuthorizedException.php +++ /dev/null @@ -1,14 +0,0 @@ -getRequest()->getAttribute('anr'); + $result = $this->anrExportService->export($anr, $data); + + return $this->prepareJsonExportResponse($result['filename'], $result['content'], !empty($data['password'])); + } +} diff --git a/src/Export/Controller/ApiAnrInstancesExportController.php b/src/Export/Controller/ApiAnrInstancesExportController.php new file mode 100755 index 00000000..814880a7 --- /dev/null +++ b/src/Export/Controller/ApiAnrInstancesExportController.php @@ -0,0 +1,31 @@ +getRequest()->getAttribute('anr'); + $result = $this->anrInstanceExportService->export($anr, $data); + + return $this->prepareJsonExportResponse($result['filename'], $result['content'], !empty($data['password'])); + } +} diff --git a/src/Export/Controller/ApiAnrObjectsExportController.php b/src/Export/Controller/ApiAnrObjectsExportController.php new file mode 100755 index 00000000..b426f71a --- /dev/null +++ b/src/Export/Controller/ApiAnrObjectsExportController.php @@ -0,0 +1,34 @@ +getRequest()->getAttribute('anr'); + $result = $this->anrObjectExportService->export($anr, $data); + + return $this->prepareJsonExportResponse($result['filename'], $result['content'], !empty($data['password'])); + } +} diff --git a/src/Export/Controller/Traits/ExportResponseControllerTrait.php b/src/Export/Controller/Traits/ExportResponseControllerTrait.php new file mode 100644 index 00000000..4874865d --- /dev/null +++ b/src/Export/Controller/Traits/ExportResponseControllerTrait.php @@ -0,0 +1,59 @@ + $contentType, + 'Content-Length' => strlen($output), + 'Content-Disposition' => 'attachment; filename="' . $filename . $extension . '"', + ]); + } + + private function prepareCsvExportResponse(string $output): ResponseInterface + { + $stream = fopen('php://memory', 'rb+'); + fwrite($stream, $output); + rewind($stream); + + return new Response($stream, 200, [ + 'Content-Type' => 'text/csv; charset=utf-8', + 'Content-Length' => strlen($output), + ]); + } + + private function prepareWordExportResponse(string $filename, string $output): ResponseInterface + { + $stream = fopen('php://memory', 'rb+'); + fwrite($stream, $output); + rewind($stream); + + return new Response($stream, 200, [ + 'Content-Type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'Content-Length' => strlen($output), + 'Content-Disposition' => 'attachment; filename="' . utf8_decode($filename) . '"', + ]); + } +} diff --git a/src/Export/Service/AnrExportService.php b/src/Export/Service/AnrExportService.php new file mode 100644 index 00000000..a605884b --- /dev/null +++ b/src/Export/Service/AnrExportService.php @@ -0,0 +1,557 @@ + {the generated filename}, + * 'content' => {json encoded string, encrypted if password is set} + * ] + */ + public function export(Entity\Anr $anr, array $exportParams): array + { + $jsonResult = json_encode($this->prepareExportData($anr, $exportParams), JSON_THROW_ON_ERROR); + + return [ + 'filename' => preg_replace("/[^a-z0-9\._-]+/i", '', $anr->getLabel()), + 'content' => empty($exportParams['password']) + ? $jsonResult + : $this->encrypt($jsonResult, $exportParams['password']), + ]; + } + + private function prepareExportData(Entity\Anr $anr, array $exportParams): array + { + $withEval = !empty($exportParams['assessments']); + $withControls = $withEval && !empty($exportParams['controls']); + $withRecommendations = $withEval && !empty($exportParams['recommendations']); + $withMethodSteps = $withEval && !empty($exportParams['methodSteps']); + $withInterviews = $withEval && !empty($exportParams['interviews']); + $withSoas = $withEval && !empty($exportParams['soas']); + $withRecords = $withEval && !empty($exportParams['records']); + $withLibrary = !empty($exportParams['assetsLibrary']); + $withKnowledgeBase = !empty($exportParams['knowledgeBase']); + + return [ + 'type' => 'anr', + 'monarc_version' => $this->configService->getAppVersion()['appVersion'], + 'exportDatetime' => (new \DateTime())->format('Y-m-d H:i:s'), + 'withEval' => $withEval, + 'withControls' => $withControls, + 'withRecommendations' => $withRecommendations, + 'withMethodSteps' => $withMethodSteps, + 'withInterviews' => $withInterviews, + 'withSoas' => $withSoas, + 'withRecords' => $withRecords, + 'withLibrary' => $withLibrary, + 'withKnowledgeBase' => $withKnowledgeBase, + 'languageCode' => $anr->getLanguageCode(), + 'languageIndex' => $anr->getLanguage(), + 'knowledgeBase' => $withKnowledgeBase || $withSoas ? $this->prepareKnowledgeBaseData( + $anr, + $withEval, + $withControls, + $withRecommendations, + !$withKnowledgeBase + ) : [], + 'library' => $withLibrary ? $this->prepareLibraryData($anr, !$withKnowledgeBase) : [], + 'instances' => $this->prepareInstancesData( + $anr, + !$withLibrary, + !$withKnowledgeBase, + $withEval, + $withControls, + $withRecommendations + ), + 'anrInstanceMetadataFields' => $this->prepareAnrInstanceMetadataFieldsData($anr), + 'scales' => $withEval ? $this->prepareScalesData($anr) : [], + 'operationalRiskScales' => $withEval ? $this->prepareOperationalRiskScalesData($anr) : [], + 'soaScaleComments' => $withSoas ? $this->prepareSoaScaleCommentsData($anr) : [], + 'soas' => $withSoas ? $this->prepareSoasData($anr) : [], + 'method' => $withMethodSteps ? $this->prepareMethodData($anr, !$withKnowledgeBase) : [], + 'thresholds' => $withEval ? $this->prepareAnrTrashholdsData($anr) : [], + 'interviews' => $withInterviews ? $this->prepareInterviewsData($anr) : [], + 'gdprRecords' => $withRecords ? $this->prepareGdprRecordsData($anr) : [], + ]; + } + + private function prepareAnrInstanceMetadataFieldsData(Entity\Anr $anr): array + { + $result = []; + /** @var Entity\AnrInstanceMetadataField $anrInstanceMetadata */ + foreach ($this->anrInstanceMetadataFieldTable->findByAnr($anr) as $anrInstanceMetadata) { + $result[] = [ + 'label' => $anrInstanceMetadata->getLabel(), + 'isDeletable' => $anrInstanceMetadata->isDeletable(), + ]; + } + + return $result; + } + + private function prepareKnowledgeBaseData( + Entity\Anr $anr, + bool $withEval, + bool $withControls, + bool $withRecommendations, + bool $onlyWithReferentials + ): array { + if ($onlyWithReferentials) { + return [ + 'assets' => [], + 'threats' => [], + 'vulnerabilities' => [], + 'referentials' => $this->prepareReferentialsData($anr), + 'informationRisks' => [], + 'rolfTags' => [], + 'operationalRisks' => [], + 'recommendationSets' => [], + ]; + } + + return [ + 'assets' => $this->prepareAssetsData($anr), + 'threats' => $this->prepareThreatsData($anr, $withEval), + 'vulnerabilities' => $this->prepareVulnerabilitiesData($anr), + 'referentials' => $this->prepareReferentialsData($anr), + 'informationRisks' => $this->prepareInformationRisksData($anr, $withEval, $withControls), + 'rolfTags' => $this->prepareRolfTagsData($anr), + 'operationalRisks' => $this->prepareOperationalRisksData($anr, $withControls), + 'recommendationSets' => $this->prepareRecommendationSetsData($anr, $withRecommendations), + ]; + } + + private function prepareAssetsData(Entity\Anr $anr): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\Asset $asset */ + foreach ($this->assetTable->findByAnr($anr) as $asset) { + $result[] = $this->prepareAssetData($asset, $languageIndex); + } + + return $result; + } + + private function prepareThreatsData(Entity\Anr $anr, bool $withEval): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\Threat $threat */ + foreach ($this->threatTable->findByAnr($anr) as $threat) { + $result[] = $this->prepareThreatData($threat, $languageIndex, $withEval); + } + + return $result; + } + + private function prepareVulnerabilitiesData(Entity\Anr $anr): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\Vulnerability $vulnerability */ + foreach ($this->vulnerabilityTable->findByAnr($anr) as $vulnerability) { + $result[] = $this->prepareVulnerabilityData($vulnerability, $languageIndex); + } + + return $result; + } + + private function prepareInformationRisksData(Entity\Anr $anr, bool $withEval, bool $withControls): array + { + $result = []; + /** @var Entity\Amv $amv */ + foreach ($this->amvTable->findByAnr($anr) as $amv) { + $result[] = $this->prepareInformationRiskData($amv, $withEval, $withControls, false); + } + + return $result; + } + + private function prepareRolfTagsData(Entity\Anr $anr): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\RolfTag $rolfTag */ + foreach ($this->rolfTagTable->findByAnr($anr) as $rolfTag) { + $result[] = [ + 'id' => $rolfTag->getId(), + 'code' => $rolfTag->getCode(), + 'label' => $rolfTag->getLabel($languageIndex), + ]; + } + + return $result; + } + + private function prepareOperationalRisksData(Entity\Anr $anr, bool $withControls): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\RolfRisk $rolfRisk */ + foreach ($this->rolfRiskTable->findByAnr($anr) as $rolfRisk) { + $result[] = $this->prepareOperationalRiskData($rolfRisk, $languageIndex, $withControls, false); + } + + return $result; + } + + private function prepareReferentialsData(Entity\Anr $anr): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\Referential $referential */ + foreach ($this->referentialTable->findByAnr($anr) as $referential) { + $measuresData = []; + foreach ($referential->getMeasures() as $measure) { + /* Include linked measures to the prepared result. */ + $measuresData[] = $this->prepareMeasureData($measure, $languageIndex, true); + } + + $result[] = [ + 'uuid' => $referential->getUuid(), + 'label' => $referential->getLabel($languageIndex), + 'measures' => $measuresData, + ]; + } + + return $result; + } + + 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, $includePositions); + } + if (!empty($recommendationsData)) { + $result[] = [ + 'uuid' => $recommendationSet->getUuid(), + 'label' => $recommendationSet->getLabel(), + 'recommendations' => $recommendationsData, + ]; + } + } + + return $result; + } + + private function prepareLibraryData(Entity\Anr $anr, bool $addRolfRisksInObjects): array + { + return [ + 'categories' => $this->prepareCategoriesAndObjects($anr, $addRolfRisksInObjects), + ]; + } + + private function prepareCategoriesAndObjects(Entity\Anr $anr, bool $addRolfRisksInObjects): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + foreach ($this->objectCategoryTable->findRootCategoriesByAnrOrderedByPosition($anr) as $objectCategory) { + $result[] = $this->prepareCategoryData($objectCategory, $languageIndex, true, $addRolfRisksInObjects); + } + + return $result; + } + + private function prepareChildrenCategoriesData( + Entity\ObjectCategory $objectCategory, + int $languageIndex, + bool $addRolfRisksInObjects + ): array { + $result = []; + foreach ($objectCategory->getChildren() as $childObjectCategory) { + $result[] = $this->prepareCategoryData($childObjectCategory, $languageIndex, false, $addRolfRisksInObjects); + } + + return $result; + } + + private function prepareObjectsDataOfCategory( + Entity\ObjectCategory $objectCategory, + int $languageIndex, + bool $addRolfRisksInObjects + ): array { + $result = []; + foreach ($objectCategory->getObjects() as $object) { + $result[] = $this->prepareObjectData($object, $languageIndex, false, false, $addRolfRisksInObjects); + } + + return $result; + } + + private function prepareCategoryData( + Entity\ObjectCategory $objectCategory, + int $languageIndex, + bool $isRoot, + bool $addRolfRisksInObjects + ): array { + return [ + 'label' => $objectCategory->getLabel($languageIndex), + 'children' => $this->prepareChildrenCategoriesData($objectCategory, $languageIndex, $addRolfRisksInObjects), + 'objects' => $this->prepareObjectsDataOfCategory($objectCategory, $languageIndex, $addRolfRisksInObjects), + 'position' => $objectCategory->getPosition(), + 'isRoot' => $isRoot, + ]; + } + + private function prepareInstancesData( + Entity\Anr $anr, + bool $includeObjectData, + bool $includeCompleteInformationRisksData, + bool $withEval, + bool $withControls, + bool $withRecommendations + ): array { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\Instance $instance */ + foreach ($this->instanceTable->findRootInstancesByAnrAndOrderByPosition($anr) as $instance) { + $result[] = $this->prepareInstanceData( + $instance, + $languageIndex, + $includeObjectData, + $includeCompleteInformationRisksData, + $withEval, + $withControls, + $withRecommendations, + ); + } + + return $result; + } + + private function prepareScalesData(Entity\Anr $anr): array + { + $result = []; + $languageIndex = $anr->getLanguage(); + /** @var Entity\Scale $scale */ + foreach ($this->scaleTable->findByAnr($anr) as $scale) { + $result[$scale->getType()] = $this->prepareScaleData($scale, $languageIndex); + } + + return $result; + } + + private function prepareOperationalRiskScalesData(Entity\Anr $anr): array + { + $result = []; + /** @var Entity\OperationalRiskScale $operationalRiskScale */ + foreach ($this->operationalRiskScaleTable->findByAnr($anr) as $operationalRiskScale) { + $result[$operationalRiskScale->getType()] = $this->prepareOperationalRiskScaleData($operationalRiskScale); + } + + return $result; + } + + private function prepareSoaScaleCommentsData(Entity\Anr $anr): array + { + $result = []; + /** @var Entity\SoaScaleComment $soaScaleComment */ + foreach ($this->soaScaleCommentTable->findByAnrOrderByIndex($anr) as $soaScaleComment) { + if (!$soaScaleComment->isHidden()) { + $result[] = [ + 'scaleIndex' => $soaScaleComment->getScaleIndex(), + 'isHidden' => $soaScaleComment->isHidden(), + 'colour' => $soaScaleComment->getColour(), + 'comment' => $soaScaleComment->getComment(), + ]; + } + } + + return $result; + } + + private function prepareSoasData(Entity\Anr $anr): array + { + $result = []; + /** @var Entity\Soa $soa */ + foreach ($this->soaTable->findByAnr($anr) as $soa) { + $result[] = [ + 'remarks' => $soa->getRemarks(), + 'evidences' => $soa->getEvidences(), + 'actions' => $soa->getActions(), + 'EX' => $soa->getEx(), + 'LR' => $soa->getLr(), + 'CO' => $soa->getCo(), + 'BR' => $soa->getBr(), + 'BP' => $soa->getBp(), + 'RRA' => $soa->getRra(), + 'soaScaleCommentIndex' => $soa->getSoaScaleComment()?->getScaleIndex(), + 'measureUuid' => $soa->getMeasure()->getUuid(), + ]; + } + + return $result; + } + + /** The threats' data is only needed when the Knowledge Base is not exported. */ + private function prepareMethodData(Entity\Anr $anr, bool $includeThreats): array + { + $languageIndex = $anr->getLanguage(); + $deliveriesData = []; + /** @var Entity\Delivery $delivery */ + foreach ($this->deliveryTable->findByAnr($anr) as $delivery) { + $docType = $delivery->getDocType(); + if (\in_array($docType, [ + Entity\Delivery::DOC_TYPE_CONTEXT_VALIDATION, + Entity\Delivery::DOC_TYPE_MODEL_VALIDATION, + Entity\Delivery::DOC_TYPE_FINAL_REPORT, + Entity\Delivery::DOC_TYPE_IMPLEMENTATION_PLAN, + Entity\Delivery::DOC_TYPE_SOA, + ], true)) { + $deliveriesData[$docType] = [ + 'id' => $delivery->getId(), + 'typedoc' => $docType, + 'name' => $delivery->getName(), + 'status' => $delivery->getStatus(), + 'version' => $delivery->getVersion(), + 'classification' => $delivery->getClassification(), + 'respCustomer' => $delivery->getRespCustomer(), + 'responsibleManager' => $delivery->getResponsibleManager(), + 'summaryEvalRisk' => $delivery->getSummaryEvalRisk(), + ]; + } + } + + $questionsData = []; + foreach ($this->questionTable->findByAnr($anr) as $question) { + $questionChoicesData = []; + foreach ($question->getQuestionChoices() as $questionChoice) { + $questionChoicesData[] = [ + 'id' => $questionChoice->getId(), + 'label' => $questionChoice->getLabel($languageIndex), + 'position' => $questionChoice->getPosition(), + ]; + } + $questionPosition = $question->getPosition(); + $questionsData[$questionPosition] = [ + 'id' => $question->getId(), + 'mode' => $question->getMode(), + 'isMultiChoice' => $question->isMultiChoice(), + 'label' => $question->getLabel($languageIndex), + 'response' => $question->getResponse(), + 'type' => $question->getType(), + 'position' => $questionPosition, + 'questionChoices' => $questionChoicesData, + ]; + } + ksort($questionsData); + + return [ + 'steps' => [ + 'initAnrContext' => $anr->getInitAnrContext(), + 'initEvalContext' => $anr->getInitEvalContext(), + 'initRiskContext' => $anr->getInitRiskContext(), + 'initDefContext' => $anr->getInitDefContext(), + 'modelImpacts' => $anr->getModelImpacts(), + 'modelSummary' => $anr->getModelSummary(), + 'evalRisks' => $anr->getEvalRisks(), + 'evalPlanRisks' => $anr->getEvalPlanRisks(), + 'manageRisks' => $anr->getManageRisks(), + ], + 'data' => [ + 'contextAnaRisk' => $anr->getContextAnaRisk(), + 'contextGestRisk' => $anr->getContextGestRisk(), + 'synthThreat' => $anr->getSynthThreat(), + 'synthAct' => $anr->getSynthAct(), + ], + 'deliveries' => $deliveriesData, + 'questions' => $questionsData, + 'threats' => $includeThreats ? $this->prepareThreatsData($anr, true) : [], + ]; + } + + private function prepareAnrTrashholdsData(Entity\Anr $anr): array + { + return [ + 'seuil1' => $anr->getSeuil1(), + 'seuil2' => $anr->getSeuil2(), + 'seuilRolf1' => $anr->getSeuilRolf1(), + 'seuilRolf2' => $anr->getSeuilRolf2(), + ]; + } + + private function prepareInterviewsData(Entity\Anr $anr): array + { + $result = []; + foreach ($this->interviewTable->findByAnr($anr) as $interview) { + $result[] = [ + 'id' => $interview->getId(), + 'date' => $interview->getDate(), + 'service' => $interview->getService(), + 'content' => $interview->getContent(), + ]; + } + + return $result; + } + + private function prepareGdprRecordsData(Entity\Anr $anr): array + { + $result = []; + $filename = ''; + foreach ($this->recordTable->findByAnr($anr) as $record) { + $result[] = $this->anrRecordService->generateExportArray($record->getId(), $filename); + } + + return $result; + } +} diff --git a/src/Export/Service/InstanceExportService.php b/src/Export/Service/InstanceExportService.php new file mode 100644 index 00000000..d05d27ae --- /dev/null +++ b/src/Export/Service/InstanceExportService.php @@ -0,0 +1,112 @@ + {the generated filename}, + * 'content' => {json encoded string, encrypted if password is set} + * ] + */ + public function export(Entity\Anr $anr, array $exportParams): array + { + if (empty($exportParams['id'])) { + throw new Exception('Instance ID is required for the export operation.', 412); + } + + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr((int)$exportParams['id'], $anr); + + $jsonResult = json_encode($this->prepareExportData($instance, $exportParams), JSON_THROW_ON_ERROR); + + return [ + 'filename' => preg_replace("/[^a-z0-9\._-]+/i", '', $instance->getName($anr->getLanguage())), + 'content' => empty($exportParams['password']) + ? $jsonResult + : $this->encrypt($jsonResult, $exportParams['password']), + ]; + } + + private function prepareExportData(Entity\Instance $instance, array $exportParams): array + { + $withEval = !empty($exportParams['assessments']); + $withControls = $withEval && !empty($exportParams['controls']); + $withRecommendations = $withEval && !empty($exportParams['recommendations']); + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); + $languageIndex = $anr->getLanguage(); + + return [ + 'type' => 'instance', + 'monarc_version' => $this->configService->getAppVersion()['appVersion'], + 'export_datetime' => (new \DateTime())->format('Y-m-d H:i:s'), + 'languageCode' => $anr->getLanguageCode(), + 'languageIndex' => $anr->getLanguage(), + 'withEval' => $withEval, + 'withControls' => $withControls, + 'withRecommendations' => $withRecommendations, + 'instance' => $this->prepareInstanceData( + $instance, + $languageIndex, + true, + true, + $withEval, + $withControls, + $withRecommendations + ), + 'scales' => $withEval ? $this->prepareScalesData($anr, $languageIndex) : [], + 'operationalRiskScales' => $withEval ? $this->prepareOperationalRiskScalesData($anr) : [], + ]; + } + + private function prepareScalesData(Entity\Anr $anr, int $languageIndex): array + { + $result = []; + /** @var Entity\Scale $scale */ + foreach ($this->scaleTable->findByAnr($anr) as $scale) { + $result[$scale->getType()] = $this->prepareScaleData($scale, $languageIndex); + } + + return $result; + } + + private function prepareOperationalRiskScalesData(Entity\Anr $anr): array + { + $result = []; + /** @var Entity\OperationalRiskScale $operationalRiskScale */ + foreach ($this->operationalRiskScaleTable->findByAnr($anr) as $operationalRiskScale) { + $result[$operationalRiskScale->getType()] = $this->prepareOperationalRiskScaleData($operationalRiskScale); + } + + return $result; + } +} diff --git a/src/Export/Service/ObjectExportService.php b/src/Export/Service/ObjectExportService.php new file mode 100644 index 00000000..de56298b --- /dev/null +++ b/src/Export/Service/ObjectExportService.php @@ -0,0 +1,223 @@ + {the generated filename}, + * 'content' => {json encoded string, encrypted if password is set} + * ] + */ + public function export(Entity\Anr $anr, array $exportParams): array + { + if (empty($exportParams['id'])) { + throw new Exception('Object ID is required for the export operation.', 412); + } + + /** @var Entity\MonarcObject $monarcObject */ + $monarcObject = $this->monarcObjectTable->findByUuidAndAnr($exportParams['id'], $anr); + + $isForMosp = !empty($exportParams['mosp']); + $jsonResult = json_encode( + $isForMosp ? $this->prepareExportDataForMosp($monarcObject) : $this->prepareExportData($monarcObject), + JSON_THROW_ON_ERROR + ); + + return [ + 'filename' => preg_replace( + "/[^a-z0-9._-]+/i", '', $monarcObject->getName($anr->getLanguage()) . ($isForMosp ? '_MOSP' : '') + ), + 'content' => empty($exportParams['password']) + ? $jsonResult + : $this->encrypt($jsonResult, $exportParams['password']), + ]; + } + + private function prepareExportData(Entity\MonarcObject $monarcObject) + { + $anr = $monarcObject->getAnr(); + + return [ + 'type' => 'object', + 'monarc_version' => $this->configService->getAppVersion()['appVersion'], + 'languageCode' => $anr->getLanguageCode(), + 'languageIndex' => $anr->getLanguage(), + 'object' => $this->prepareObjectData($monarcObject, $anr->getLanguage(), true), + ]; + } + + private function prepareExportDataForMosp(Entity\MonarcObject $monarcObject): array + { + $languageIndex = $monarcObject->getAnr()->getLanguage(); + $languageCode = $monarcObject->getAnr()->getLanguageCode(); + /** @var Entity\Asset $asset */ + $asset = $monarcObject->getAsset(); + $rolfTag = $monarcObject->getRolfTag(); + $rolfRisksData = []; + if ($rolfTag !== null) { + foreach ($rolfTag->getRisks() as $rolfRisk) { + $rolfRisksData[] = $this->prepareOperationalRiskDataForMosp($rolfRisk, $languageIndex); + } + } + $childrenObjects = []; + foreach ($monarcObject->getChildren() as $childObject) { + $childrenObjects[] = $this->prepareExportDataForMosp($childObject); + } + + return ['object' => [ + 'object' => [ + 'uuid' => $monarcObject->getUuid(), + 'scope' => $monarcObject->getScopeName(), + 'name' => $monarcObject->getName($languageIndex), + 'label' => $monarcObject->getLabel($languageIndex), + 'language' => $languageCode, + 'version' => 1, + ], + 'asset' => $asset !== null ? $this->prepareAssetDataForMosp($asset) : null, + 'rolfRisks' => $rolfRisksData, + 'rolfTags' => $rolfTag !== null + ? [['code' => $rolfTag->getCode(), 'label' => $rolfTag->getLabel($languageIndex)]] + : [], + 'children' => $childrenObjects, + ]]; + } + + private function prepareAssetDataForMosp(Entity\Asset $asset): array + { + $languageIndex = $asset->getAnr()->getLanguage(); + $languageCode = $asset->getAnr()->getLanguageCode(); + + $assetData = [ + 'asset' => [ + 'uuid' => $asset->getUuid(), + 'label' => $asset->getLabel($languageIndex), + 'description' => $asset->getDescription($languageIndex), + 'type' => $asset->getTypeName(), + 'code' => $asset->getCode(), + 'language' => $languageCode, + 'version' => 1, + ], + 'amvs' => [], + 'threats' => [], + 'vuls' => [], + 'measures' => [], + ]; + + foreach ($asset->getAmvs() as $amv) { + $amvResult = $this->prepareAmvsDataForMosp($amv, $languageIndex, $languageCode); + $assetData['amvs'] += $amvResult['amv']; + $assetData['threats'] += $amvResult['threat']; + $assetData['vuls'] += $amvResult['vulnerability']; + $assetData['measures'] += $amvResult['measures']; + } + $assetData['amvs'] = array_values($assetData['amvs']); + $assetData['threats'] = array_values($assetData['threats']); + $assetData['vuls'] = array_values($assetData['vuls']); + $assetData['measures'] = array_values($assetData['measures']); + + return $assetData; + } + + private function prepareAmvsDataForMosp(Entity\Amv $amv, int $languageIndex, string $languageCode): array + { + $measuresData = []; + foreach ($amv->getMeasures() as $measure) { + $measureUuid = $measure->getUuid(); + $measuresData[] = [ + 'uuid' => $measureUuid, + 'code' => $measure->getCode(), + 'label' => $measure->getLabel($languageIndex), + 'category' => $measure->getCategory()?->getLabel($languageIndex), + 'referential' => $measure->getReferential()->getUuid(), + 'referential_label' => $measure->getReferential()->getLabel($languageIndex), + ]; + } + $threat = $amv->getThreat(); + $vulnerability = $amv->getVulnerability(); + + return [ + 'amv' => [ + $amv->getUuid() => [ + 'uuid' => $amv->getUuid(), + 'asset' => $amv->getAsset()->getUuid(), + 'threat' => $threat->getUuid(), + 'vulnerability' => $vulnerability->getUuid(), + 'measures' => array_keys($measuresData), + ], + ], + 'threat' => [ + $threat->getUuid() => [ + 'uuid' => $threat->getUuid(), + 'label' => $threat->getLabel($languageIndex), + 'description' => $threat->getDescription($languageIndex), + 'theme' => $threat->getTheme() !== null + ? $threat->getTheme()->getLabel($languageIndex) + : '', + 'code' => $threat->getCode(), + 'c' => (bool)$threat->getConfidentiality(), + 'i' => (bool)$threat->getIntegrity(), + 'a' => (bool)$threat->getAvailability(), + 'language' => $languageCode, + ], + ], + 'vulnerability' => [ + $vulnerability->getUuid() => [ + 'uuid' => $vulnerability->getUuid(), + 'code' => $vulnerability->getCode(), + 'label' => $vulnerability->getLabel($languageIndex), + 'description' => $vulnerability->getDescription($languageIndex), + 'language' => $languageCode, + ], + ], + 'measures' => $measuresData, + ]; + } + + private function prepareOperationalRiskDataForMosp(Entity\RolfRisk $rolfRisk, int $languageIndex): array + { + $measuresData = []; + foreach ($rolfRisk->getMeasures() as $measure) { + $measuresData[] = [ + 'uuid' => $measure->getUuid(), + 'code' => $measure->getCode(), + 'label' => $measure->getLabel($languageIndex), + 'category' => $measure->getCategory()?->getLabel($languageIndex), + 'referential' => $measure->getReferential()->getUuid(), + 'referential_label' => $measure->getReferential()->getLabel($languageIndex), + ]; + } + + return [ + 'code' => $rolfRisk->getCode(), + 'label' => $rolfRisk->getLabel($languageIndex), + 'description' => $rolfRisk->getDescription($languageIndex), + 'measures' => $measuresData, + ]; + } +} diff --git a/src/Export/Service/Traits/AssetExportTrait.php b/src/Export/Service/Traits/AssetExportTrait.php new file mode 100644 index 00000000..53f3741e --- /dev/null +++ b/src/Export/Service/Traits/AssetExportTrait.php @@ -0,0 +1,32 @@ + $asset->getUuid()]; + } + + return [ + 'uuid' => $asset->getUuid(), + 'code' => $asset->getCode(), + 'label' => $asset->getLabel($languageIndex), + 'description' => $asset->getDescription($languageIndex), + 'type' => $asset->getType(), + 'status' => $asset->getStatus(), + ]; + } +} diff --git a/src/Export/Service/Traits/InformationInstanceRiskExportTrait.php b/src/Export/Service/Traits/InformationInstanceRiskExportTrait.php new file mode 100644 index 00000000..ac3e1436 --- /dev/null +++ b/src/Export/Service/Traits/InformationInstanceRiskExportTrait.php @@ -0,0 +1,72 @@ +getAmv(); + $informationRiskData = $amv === null ? null : ['uuid' => $amv->getUuid()]; + if ($includeCompleteInformationRisksData && $amv !== null) { + $informationRiskData = $this->prepareInformationRiskData($amv, $withEval, $withControls); + } + /** @var Entity\Threat $threat */ + $threat = $instanceRisk->getThreat(); + /** @var Entity\Vulnerability $vulnerability */ + $vulnerability = $instanceRisk->getVulnerability(); + $recommendationsData = []; + if ($withRecommendations) { + foreach ($instanceRisk->getRecommendationRisks() as $recommendationRisk) { + $recommendation = $recommendationRisk->getRecommendation(); + $recommendationsData[] = array_merge( + $this->prepareRecommendationData($recommendation), + ['commentAfter' => $recommendationRisk->getCommentAfter()] + ); + } + } + + return [ + 'id' => $instanceRisk->getId(), + 'informationRisk' => $informationRiskData, + 'threat' => $this->prepareThreatData($threat, $languageIndex, $withEval), + 'vulnerability' => $this->prepareVulnerabilityData($vulnerability, $languageIndex), + 'specific' => (int)$instanceRisk->isSpecific(), + 'isThreatRateNotSetOrModifiedExternally' => $withEval + ? (int)$instanceRisk->isThreatRateNotSetOrModifiedExternally() + : 1, + 'threatRate' => $withEval ? $instanceRisk->getThreatRate() : -1, + 'vulnerabilityRate' => $withEval ? $instanceRisk->getVulnerabilityRate() : -1, + 'kindOfMeasure' => $withEval ? $instanceRisk->getKindOfMeasure() : InstanceRiskSuperClass::KIND_NOT_SET, + 'reductionAmount' => $withEval ? $instanceRisk->getReductionAmount() : 0, + 'comment' => $withControls ? $instanceRisk->getComment() : '', + 'commentAfter' => $withControls ? $instanceRisk->getCommentAfter() : '', + 'cacheMaxRisk' => $withEval ? $instanceRisk->getCacheMaxRisk() : -1, + 'cacheTargetedRisk' => $withEval ? $instanceRisk->getCacheTargetedRisk() : -1, + 'riskConfidentiality' => $withEval ? $instanceRisk->getRiskConfidentiality() : -1, + 'riskIntegrity' => $withEval ? $instanceRisk->getRiskIntegrity() : -1, + 'riskAvailability' => $withEval ? $instanceRisk->getRiskAvailability() : -1, + 'context' => $withEval ? $instanceRisk->getContext() : '', + 'riskOwner' => $withEval ? $instanceRisk->getInstanceRiskOwner()?->getName() : '', + 'recommendations' => $recommendationsData, + ]; + } +} diff --git a/src/Export/Service/Traits/InformationRiskExportTrait.php b/src/Export/Service/Traits/InformationRiskExportTrait.php new file mode 100644 index 00000000..1c331e99 --- /dev/null +++ b/src/Export/Service/Traits/InformationRiskExportTrait.php @@ -0,0 +1,55 @@ +getAsset(); + /** @var Entity\Threat $threat */ + $threat = $amv->getThreat(); + /** @var Entity\Vulnerability $vulnerability */ + $vulnerability = $amv->getVulnerability(); + $languageIndex = $amv->getAnr()->getLanguage(); + + $measuresData = []; + if ($withControls) { + foreach ($amv->getMeasures() as $measure) { + $measuresData[] = $this->prepareMeasureData( + $measure, + $languageIndex, + false, + $includeCompleteRelationData + ); + } + } + + return [ + 'uuid' => $amv->getUuid(), + 'asset' => $this->prepareAssetData($asset, $languageIndex, $includeCompleteRelationData), + 'threat' => $this->prepareThreatData($threat, $languageIndex, $withEval, $includeCompleteRelationData), + 'vulnerability' => $this + ->prepareVulnerabilityData($vulnerability, $languageIndex, $includeCompleteRelationData), + 'measures' => $measuresData, + 'status' => $amv->getStatus(), + ]; + } +} diff --git a/src/Export/Service/Traits/InstanceConsequenceExportTrait.php b/src/Export/Service/Traits/InstanceConsequenceExportTrait.php new file mode 100644 index 00000000..5f6a5cae --- /dev/null +++ b/src/Export/Service/Traits/InstanceConsequenceExportTrait.php @@ -0,0 +1,33 @@ +getScaleImpactType(); + + return [ + 'id' => $instanceConsequence->getId(), + 'confidentiality' => $instanceConsequence->getConfidentiality(), + 'integrity' => $instanceConsequence->getIntegrity(), + 'availability' => $instanceConsequence->getAvailability(), + 'isHidden' => $instanceConsequence->isHidden(), + 'scaleImpactType' => $this + ->prepareScaleImpactTypeAndCommentsData($scaleImpactType, $languageIndex, false, true), + ]; + } +} diff --git a/src/Export/Service/Traits/InstanceExportTrait.php b/src/Export/Service/Traits/InstanceExportTrait.php new file mode 100644 index 00000000..24d458ff --- /dev/null +++ b/src/Export/Service/Traits/InstanceExportTrait.php @@ -0,0 +1,179 @@ +getObject(); + /** @var Entity\Asset $asset */ + $asset = $instance->getAsset(); + + return [ + 'name' => $instance->getName($languageIndex), + 'label' => $instance->getLabel($languageIndex), + 'level' => $instance->getLevel(), + 'position' => $instance->getPosition(), + 'confidentiality' => $withEval ? $instance->getConfidentiality() : -1, + 'integrity' => $withEval ? $instance->getIntegrity() : -1, + 'availability' => $withEval ? $instance->getAvailability() : -1, + 'isConfidentialityInherited' => $withEval ? (int)$instance->isConfidentialityInherited() : 1, + 'isIntegrityInherited' => $withEval ? (int)$instance->isIntegrityInherited() : 1, + 'isAvailabilityInherited' => $withEval ? (int)$instance->isAvailabilityInherited() : 1, + 'asset' => $this->prepareAssetData($asset, $languageIndex), + /* For Anr and Instance export instanceRisks are added to the instance, so not needed in AMVs in asset. */ + 'object' => $includeCompleteObjectData + ? $this->prepareObjectData($object, $languageIndex, false) + : ['uuid' => $instance->getObject()->getUuid()], + 'instanceMetadata' => $withEval ? $this->prepareInstanceMetadataData($instance) : [], + 'instanceRisks' => $this->prepareInformationInstanceRisksData( + $instance, + $languageIndex, + $includeCompleteInformationRisksData, + $withEval, + $withControls, + $withRecommendations + ), + 'operationalInstanceRisks' => $this->prepareOperationalInstanceRisksData( + $instance, + $languageIndex, + $withEval, + $withControls, + $withRecommendations + ), + 'instancesConsequences' => $this->prepareInstanceConsequencesData($instance, $languageIndex), + 'children' => $this->prepareChildrenInstancesData( + $instance, + $languageIndex, + $includeCompleteObjectData, + $includeCompleteInformationRisksData, + $withEval, + $withControls, + $withRecommendations + ), + ]; + } + + private function prepareInstanceMetadataData(Entity\Instance $instance): array + { + $result = []; + foreach ($instance->getInstanceMetadata() as $instanceMetadata) { + $result[] = [ + 'anrInstanceMetadataField' => [ + 'label' => $instanceMetadata->getAnrInstanceMetadataField()->getLabel(), + ], + 'comment' => $instanceMetadata->getComment(), + ]; + } + + return $result; + } + + private function prepareChildrenInstancesData( + Entity\Instance $instance, + int $languageIndex, + bool $includeCompleteObjectData, + bool $includeCompleteInformationRisksData, + bool $withEval, + bool $withControls, + bool $withRecommendations + ): array { + $result = []; + /** @var Entity\Instance $childInstance */ + foreach ($instance->getChildren() as $childInstance) { + $result[] = $this->prepareInstanceData( + $childInstance, + $languageIndex, + $includeCompleteObjectData, + $includeCompleteInformationRisksData, + $withEval, + $withControls, + $withRecommendations + ); + } + + return $result; + } + + private function prepareInformationInstanceRisksData( + Entity\Instance $instance, + int $languageIndex, + bool $includeCompleteInformationRisksData, + bool $withEval, + bool $withControls, + bool $withRecommendations + ): array { + $result = []; + /** @var Entity\InstanceRisk $operationalInstanceRisk */ + foreach ($instance->getInstanceRisks() as $instanceRisk) { + $result[] = $this->prepareInformationInstanceRiskData( + $instanceRisk, + $languageIndex, + $includeCompleteInformationRisksData, + $withEval, + $withControls, + $withRecommendations + ); + } + + return $result; + } + + private function prepareOperationalInstanceRisksData( + Entity\Instance $instance, + int $languageIndex, + bool $withEval, + bool $withControls, + bool $withRecommendations + ): array { + $result = []; + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + foreach ($instance->getOperationalInstanceRisks() as $operationalInstanceRisk) { + $result[] = $this->prepareOperationalInstanceRiskData( + $operationalInstanceRisk, + $languageIndex, + $withEval, + $withControls, + $withRecommendations + ); + } + + return $result; + } + + private function prepareInstanceConsequencesData(Entity\Instance $instance, int $languageIndex): array + { + $result = []; + /** @var Entity\InstanceConsequence $instanceConsequence */ + foreach ($instance->getInstanceConsequences() as $instanceConsequence) { + $result[] = $this->prepareInstanceConsequenceData( + $instanceConsequence, + $languageIndex + ); + } + + return $result; + } +} diff --git a/src/Export/Service/Traits/MeasureExportTrait.php b/src/Export/Service/Traits/MeasureExportTrait.php new file mode 100644 index 00000000..f6448fa2 --- /dev/null +++ b/src/Export/Service/Traits/MeasureExportTrait.php @@ -0,0 +1,48 @@ + $measure->getUuid()]; + } + + $result = [ + 'uuid' => $measure->getUuid(), + 'code' => $measure->getCode(), + 'label' => $measure->getLabel($languageIndex), + 'referential' => [ + 'uuid' => $measure->getReferential()->getUuid(), + 'label' => $measure->getReferential()->getLabel($languageIndex) + ], + 'category' => $measure->getCategory() === null ? null : [ + 'label' => $measure->getCategory()->getLabel($languageIndex), + ], + ]; + + if ($includeLinks) { + foreach ($measure->getLinkedMeasures() as $linkedMeasure) { + $result['linkedMeasures'][] = [ + 'uuid' => $linkedMeasure->getUuid(), + 'referential' => ['uuid' => $linkedMeasure->getReferential()->getUuid()], + ]; + } + } + + return $result; + } +} diff --git a/src/Export/Service/Traits/ObjectExportTrait.php b/src/Export/Service/Traits/ObjectExportTrait.php new file mode 100644 index 00000000..25f7966d --- /dev/null +++ b/src/Export/Service/Traits/ObjectExportTrait.php @@ -0,0 +1,114 @@ +getCategory(); + /** @var Entity\Asset $asset */ + $asset = $object->getAsset(); + $assetData = $this->prepareAssetData($asset, $languageIndex); + if ($addAmvsToAssetData) { + $assetData['informationRisks'] = []; + foreach ($asset->getAmvs() as $amv) { + $assetData['informationRisks'][] = $this->prepareInformationRiskData($amv); + } + } + $rolfTagData = null; + if ($object->getRolfTag() !== null) { + /** @var Entity\RolfTag $rolfTag */ + $rolfTag = $object->getRolfTag(); + $rolfTagData = [ + 'id' => $rolfTag->getId(), + 'code' => $rolfTag->getCode(), + 'label' => $rolfTag->getLabel($languageIndex), + ]; + if ($addRolfRisksInObjects) { + $rolfTagData['rolfRisks'] = $this->prepareRolfRisksData($rolfTag); + } + } + + $result = [ + 'uuid' => $object->getUuid(), + 'name' => $object->getName($languageIndex), + 'label' => $object->getLabel($languageIndex), + 'mode' => $object->getMode(), + 'scope' => $object->getScope(), + 'asset' => $assetData, + 'rolfTag' => $rolfTagData, + 'children' => $object->hasChildren() ? $this->prepareChildrenObjectsData( + $object, + $languageIndex, + $addAmvsToAssetData, + $addRolfRisksInObjects + ) : [], + ]; + if ($includeCategory) { + $result['category'] = $objectCategory !== null + ? $this->prepareCategoryAndParentsData($objectCategory) + : null; + } + + return $result; + } + + private function prepareCategoryAndParentsData(Entity\ObjectCategory $objectCategory): array + { + /** @var ?Entity\ObjectCategory $parentCategory */ + $parentCategory = $objectCategory->getParent(); + + return [ + 'id' => $objectCategory->getId(), + 'label' => $objectCategory->getLabel($objectCategory->getAnr()->getLanguage()), + 'position' => $objectCategory->getPosition(), + 'parent' => $parentCategory !== null ? $this->prepareCategoryAndParentsData($parentCategory) : null, + ]; + } + + private function prepareChildrenObjectsData( + Entity\MonarcObject $object, + int $languageIndex, + bool $addAmvsToAssetData, + bool $addRolfRisksInObjects + ): array { + $result = []; + foreach ($object->getChildrenLinks() as $childLink) { + /** @var Entity\MonarcObject $childObject */ + $childObject = $childLink->getChild(); + $result[] = $this + ->prepareObjectData($childObject, $languageIndex, $addAmvsToAssetData, true, $addRolfRisksInObjects); + } + + return $result; + } + + private function prepareRolfRisksData(Entity\RolfTag $rolfTag): array + { + $rolfRisksData = []; + $languageIndex = $rolfTag->getAnr()->getLanguage(); + foreach ($rolfTag->getRisks() as $rolfRisk) { + $rolfRisksData[] = $this->prepareOperationalRiskData($rolfRisk, $languageIndex); + } + + return $rolfRisksData; + } +} diff --git a/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php b/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php new file mode 100644 index 00000000..fae7602b --- /dev/null +++ b/src/Export/Service/Traits/OperationalInstanceRiskExportTrait.php @@ -0,0 +1,77 @@ +getRolfRisk(); + $recommendationsData = []; + if ($withRecommendations) { + foreach ($operationalInstanceRisk->getRecommendationRisks() as $recommendationRisk) { + $recommendation = $recommendationRisk->getRecommendation(); + $recommendationsData[] = array_merge( + $this->prepareRecommendationData($recommendation), + ['commentAfter' => $recommendationRisk->getCommentAfter()] + ); + } + } + $operationalInstanceRiskScales = []; + if ($withEval) { + foreach ($operationalInstanceRisk->getOperationalInstanceRiskScales() as $instanceRiskScale) { + $scaleTypeId = $instanceRiskScale->getOperationalRiskScaleType()->getId(); + $operationalInstanceRiskScales[$scaleTypeId] = [ + 'operationalRiskScaleTypeId' => $scaleTypeId, + 'netValue' => $instanceRiskScale->getNetValue(), + 'brutValue' => $instanceRiskScale->getBrutValue(), + 'targetedValue' => $instanceRiskScale->getTargetedValue(), + ]; + } + } + + return [ + 'id' => $operationalInstanceRisk->getId(), + '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, + 'netProb' => $withEval ? $operationalInstanceRisk->getNetProb() : -1, + 'targetedProb' => $withEval ? $operationalInstanceRisk->getTargetedProb() : -1, + 'cacheBrutRisk' => $withEval ? $operationalInstanceRisk->getCacheBrutRisk() : -1, + 'cacheNetRisk' => $withEval ? $operationalInstanceRisk->getCacheNetRisk() : -1, + 'cacheTargetedRisk' => $withEval ? $operationalInstanceRisk->getCacheTargetedRisk() : -1, + 'kindOfMeasure' => $withEval + ? $operationalInstanceRisk->getKindOfMeasure() + : InstanceRiskOpSuperClass::KIND_NOT_SET, + 'comment' => $withControls ? $operationalInstanceRisk->getComment() : '', + 'mitigation' => $withEval ? $operationalInstanceRisk->getMitigation() : '', + 'specific' => $operationalInstanceRisk->getSpecific(), + 'context' => $withEval ? $operationalInstanceRisk->getContext() : '', + 'riskOwner' => $withEval && $operationalInstanceRisk->getInstanceRiskOwner() !== null + ? $operationalInstanceRisk->getInstanceRiskOwner()->getName() + : '', + 'recommendations' => $recommendationsData, + 'operationalInstanceRiskScales' => $operationalInstanceRiskScales, + ]; + } +} diff --git a/src/Export/Service/Traits/OperationalRiskExportTrait.php b/src/Export/Service/Traits/OperationalRiskExportTrait.php new file mode 100644 index 00000000..c858f1eb --- /dev/null +++ b/src/Export/Service/Traits/OperationalRiskExportTrait.php @@ -0,0 +1,50 @@ +getMeasures() as $measure) { + $measuresData[] = $this->prepareMeasureData( + $measure, + $languageIndex, + false, + $includeCompleteRelationData + ); + } + } + $rolfTagsData = []; + foreach ($rolfRisk->getTags() as $rolfTag) { + $rolfTagsData[] = [ + 'code' => $rolfTag->getCode(), + 'label' => $rolfTag->getLabel($languageIndex), + ]; + } + + return [ + 'id' => $rolfRisk->getId(), + 'code' => $rolfRisk->getCode(), + 'label' => $rolfRisk->getLabel($languageIndex), + 'description' => $rolfRisk->getDescription($languageIndex), + 'rolfTags' => $rolfTagsData, + 'measures' => $measuresData, + ]; + } +} diff --git a/src/Export/Service/Traits/OperationalRiskScaleExportTrait.php b/src/Export/Service/Traits/OperationalRiskScaleExportTrait.php new file mode 100644 index 00000000..e8ee2af0 --- /dev/null +++ b/src/Export/Service/Traits/OperationalRiskScaleExportTrait.php @@ -0,0 +1,62 @@ +getOperationalRiskScaleTypes() as $scaleType) { + $scaleTypeComments = []; + foreach ($scaleType->getOperationalRiskScaleComments() as $scaleTypeComment) { + $scaleTypeComments[] = $this->prepareOperationalRiskScaleCommentData( + $scaleTypeComment + ); + } + + $scaleTypes[] = [ + 'id' => $scaleType->getId(), + 'label' => $scaleType->getLabel(), + 'isHidden' => $scaleType->isHidden(), + 'operationalRiskScaleComments' => $scaleTypeComments, + ]; + } + + $scaleComments = []; + foreach ($operationalRiskScale->getOperationalRiskScaleComments() as $scaleComment) { + if ($scaleComment->getOperationalRiskScaleType() !== null) { + continue; + } + + $scaleComments[] = $this->prepareOperationalRiskScaleCommentData($scaleComment); + } + + return [ + 'min' => $operationalRiskScale->getMin(), + 'max' => $operationalRiskScale->getMax(), + 'type' => $operationalRiskScale->getType(), + 'operationalRiskScaleTypes' => $scaleTypes, + 'operationalRiskScaleComments' => $scaleComments, + ]; + } + + private function prepareOperationalRiskScaleCommentData(Entity\OperationalRiskScaleComment $scaleComment): array + { + return [ + 'id' => $scaleComment->getId(), + 'scaleIndex' => $scaleComment->getScaleIndex(), + 'scaleValue' => $scaleComment->getScaleValue(), + 'isHidden' => $scaleComment->isHidden(), + 'comment' => $scaleComment->getComment(), + ]; + } +} diff --git a/src/Export/Service/Traits/RecommendationExportTrait.php b/src/Export/Service/Traits/RecommendationExportTrait.php new file mode 100644 index 00000000..89931e10 --- /dev/null +++ b/src/Export/Service/Traits/RecommendationExportTrait.php @@ -0,0 +1,42 @@ + $recommendation->getUuid(), + 'code' => $recommendation->getCode(), + 'description' => $recommendation->getDescription(), + 'importance' => $recommendation->getImportance(), + 'comment' => $recommendation->getComment(), + 'status' => $recommendation->getStatus(), + 'responsible' => $recommendation->getResponsible(), + 'duedate' => $recommendation->getDueDate()?->format('Y-m-d'), + 'counterTreated' => $recommendation->getCounterTreated(), + ]; + if ($includeRecommendationSetData) { + $result['recommendationSet'] = [ + 'uuid' => $recommendation->getRecommendationSet()->getUuid(), + 'label' => $recommendation->getRecommendationSet()->getLabel(), + ]; + } + if ($includePosition) { + $result['position'] = $recommendation->getPosition(); + } + + return $result; + } +} diff --git a/src/Export/Service/Traits/ScaleExportTrait.php b/src/Export/Service/Traits/ScaleExportTrait.php new file mode 100644 index 00000000..d678f03c --- /dev/null +++ b/src/Export/Service/Traits/ScaleExportTrait.php @@ -0,0 +1,48 @@ +getScaleComments() as $scaleComment) { + if ($scaleComment->getScaleImpactType() === null) { + $scaleCommentsData[] = [ + 'scaleIndex' => $scaleComment->getScaleIndex(), + 'scaleValue' => $scaleComment->getScaleValue(), + 'comment' => $scaleComment->getComment($languageIndex), + ]; + } + } + + return [ + 'min' => $scale->getMin(), + 'max' => $scale->getMax(), + 'type' => $scale->getType(), + 'scaleImpactTypes' => $this->prepareScaleImpactTypesData($scale, $languageIndex), + 'scaleComments' => $scaleCommentsData, + ]; + } + + private function prepareScaleImpactTypesData(Entity\Scale $scale, int $languageIndex): array + { + $result = []; + foreach ($scale->getScaleImpactTypes() as $scaleImpactType) { + $result[] = $this->prepareScaleImpactTypeAndCommentsData($scaleImpactType, $languageIndex, true, false); + } + + return $result; + } +} diff --git a/src/Export/Service/Traits/ScaleImpactTypeExportTrait.php b/src/Export/Service/Traits/ScaleImpactTypeExportTrait.php new file mode 100644 index 00000000..01364475 --- /dev/null +++ b/src/Export/Service/Traits/ScaleImpactTypeExportTrait.php @@ -0,0 +1,48 @@ +getScaleComments() as $scaleComment) { + $scaleComments[] = [ + 'scaleIndex' => $scaleComment->getScaleIndex(), + 'scaleValue' => $scaleComment->getScaleValue(), + 'comment' => $scaleComment->getComment($languageIndex), + ]; + } + } + + $result = [ + 'id' => $scaleImpactType->getId(), + 'type' => $scaleImpactType->getType(), + 'label' => $scaleImpactType->getLabel($languageIndex), + 'isSys' => $scaleImpactType->isSys(), + 'isHidden' => $scaleImpactType->isHidden(), + 'scaleComments' => $scaleComments, + ]; + if ($includeScale) { + $result['scale'] = [ + 'id' => $scaleImpactType->getScale()->getId(), + 'type' => $scaleImpactType->getScale()->getType(), + ]; + } + + return $result; + } +} diff --git a/src/Export/Service/Traits/ThreatExportTrait.php b/src/Export/Service/Traits/ThreatExportTrait.php new file mode 100644 index 00000000..4ddd7254 --- /dev/null +++ b/src/Export/Service/Traits/ThreatExportTrait.php @@ -0,0 +1,44 @@ + $threat->getUuid()]; + } + + return [ + 'uuid' => $threat->getUuid(), + 'label' => $threat->getLabel($languageIndex), + 'description' => $threat->getDescription($languageIndex), + 'theme' => $threat->getTheme() !== null ? [ + 'id' => $threat->getTheme()->getId(), + 'label' => $threat->getTheme()->getLabel($languageIndex), + ] : null, + 'status' => $threat->getStatus(), + 'mode' => $threat->getMode(), + 'code' => $threat->getCode(), + 'confidentiality' => $threat->getConfidentiality(), + 'integrity' => $threat->getIntegrity(), + 'availability' => $threat->getAvailability(), + 'trend' => $withEval ? $threat->getTrend() : 0, + 'comment' => $withEval ? $threat->getComment() : '', + 'qualification' => $withEval ? $threat->getQualification() : -1, + ]; + } +} diff --git a/src/Export/Service/Traits/VulnerabilityExportTrait.php b/src/Export/Service/Traits/VulnerabilityExportTrait.php new file mode 100644 index 00000000..fb7eabbc --- /dev/null +++ b/src/Export/Service/Traits/VulnerabilityExportTrait.php @@ -0,0 +1,31 @@ + $vulnerability->getUuid()]; + } + + return [ + 'uuid' => $vulnerability->getUuid(), + 'label' => $vulnerability->getLabel($languageIndex), + 'description' => $vulnerability->getDescription($languageIndex), + 'code' => $vulnerability->getCode(), + 'status' => $vulnerability->getStatus(), + ]; + } +} diff --git a/src/Helper/EncryptDecryptHelperTrait.php b/src/Helper/EncryptDecryptHelperTrait.php deleted file mode 100644 index db29ca49..00000000 --- a/src/Helper/EncryptDecryptHelperTrait.php +++ /dev/null @@ -1,44 +0,0 @@ -cronTaskService->getNextTaskByName(CronTask::NAME_INSTANCE_IMPORT)) { @@ -85,14 +84,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $password = base64_decode($params['password']); } - $this->anrTable->saveEntity($anr->setStatus(AnrSuperClass::STATUS_UNDER_IMPORT)); + $this->anrTable->save($anr->setStatus(AnrSuperClass::STATUS_UNDER_IMPORT)); $ids = []; $errors = []; try { /* Create a Snapshot as a backup. */ - if (!empty($params['createSnapshot'])) { - $this->snapshotService->create(['anr' => $anr, 'comment' => 'Import Backup #' . time()]); - } + $this->snapshotService->create($anr, ['comment' => 'Import Backup #' . time()]); [$ids, $errors] = $this->instanceImportService->importFromFile($anrId, [ 'file' => [[ 'tmp_name' => $params['fileNameWithPath'], @@ -102,7 +99,6 @@ protected function execute(InputInterface $input, OutputInterface $output) 'mode' => $params['mode'] ?? null, 'idparent' => $params['idparent'] ?? null, ]); - $this->instanceImportService->cleanCache(); } catch (\Throwable $e) { $errors[] = $e->getMessage(); $errors[] = 'Error Trace:'; @@ -111,12 +107,12 @@ protected function execute(InputInterface $input, OutputInterface $output) if (!empty($errors)) { $this->cronTaskService->setFailure($cronTask, implode("\n", $errors)); - $this->anrTable->saveEntity($anr->setStatus(AnrSuperClass::STATUS_IMPORT_ERROR)); + $this->anrTable->save($anr->setStatus(AnrSuperClass::STATUS_IMPORT_ERROR)); return 1; } - $this->anrTable->saveEntity($anr->setStatus(AnrSuperClass::STATUS_ACTIVE)); + $this->anrTable->save($anr->setStatus(AnrSuperClass::STATUS_ACTIVE)); $this->cronTaskService->setSuccessful( $cronTask, 'The Analysis was successfully imported with anr ID ' . $anrId diff --git a/src/Import/Controller/ApiAnrInstancesImportController.php b/src/Import/Controller/ApiAnrInstancesImportController.php index 6ca40430..6fabe10a 100755 --- a/src/Import/Controller/ApiAnrInstancesImportController.php +++ b/src/Import/Controller/ApiAnrInstancesImportController.php @@ -1,45 +1,39 @@ instanceImportService = $instanceImportService; - $this->importConfig = $configService->getConfigOption('import', []); - $this->cronTaskService = $cronTaskService; - $this->anrTable = $anrTable; + $this->importConfig = $configService->getConfigOption('import') ? : []; } /** @@ -47,25 +41,22 @@ public function __construct( */ public function getList() { - $anrId = (int)$this->params()->fromRoute('anrid'); - $anr = $this->anrTable->findById($anrId); + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); - return new JsonModel([ + return $this->getPreparedJsonResponse([ 'status' => $anr->getStatusName(), 'messages' => $this->cronTaskService->getResultMessagesByNameWithParam( CronTask::NAME_INSTANCE_IMPORT, - ['anrId' => $anrId] + ['anrId' => $anr->getId()] ), ]); } public function create($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } - + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); $files = $this->params()->fromFiles('file'); if (empty($files)) { throw new Exception('File missing', 412); @@ -73,7 +64,9 @@ public function create($data) $data['file'] = $files; if (!empty($this->importConfig['isBackgroundProcessActive'])) { + // TODO: move it to a service /* Upload file to process it later. */ + $anrId = $anr->getId(); $tmpFile = current($files); $fileName = $anrId . '-' . $tmpFile['name']; $fileNameWithPath = $this->moveTmpFile($tmpFile, $this->importConfig['uploadFolder'], $fileName); @@ -85,32 +78,27 @@ public function create($data) } $mode = $data['mode'] ?? 'merge'; $idparent = $data['idparent'] ?? 0; - $createSnapshot = filter_var($data['createSnapshot'], FILTER_VALIDATE_BOOLEAN); /* Create a job for the process */ $this->cronTaskService->createTask( CronTask::NAME_INSTANCE_IMPORT, - compact('anrId', 'fileNameWithPath', 'password', 'mode', 'idparent', 'createSnapshot'), + compact('anrId', 'fileNameWithPath', 'password', 'mode', 'idparent'), CronTask::PRIORITY_HIGH ); /* Set Anr status to pending. */ - $this->anrTable->saveEntity( - $this->anrTable->findById($anrId)->setStatus(AnrSuperClass::STATUS_AWAITING_OF_IMPORT) - ); + $this->anrTable->save($anr->setStatus(AnrSuperClass::STATUS_AWAITING_OF_IMPORT)); - return new JsonModel([ - 'status' => 'ok', + return $this->getSuccessfulJsonResponse([ 'isBackgroundProcess' => true, 'id' => [], 'errors' => [], ]); } - [$ids, $errors] = $this->instanceImportService->importFromFile($anrId, $data); + [$ids, $errors] = $this->instanceImportService->importFromFile($anr, $data); - return new JsonModel([ - 'status' => 'ok', + return $this->getSuccessfulJsonResponse([ 'isBackgroundProcess' => false, 'id' => $ids, 'errors' => $errors, @@ -124,22 +112,19 @@ public function create($data) */ public function deleteList($data) { - $anrId = (int)$this->params()->fromRoute('anrid'); - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); - } + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); if (!empty($this->importConfig['isBackgroundProcessActive'])) { $importCronTask = $this->cronTaskService - ->getLatestTaskByNameWithParam(CronTask::NAME_INSTANCE_IMPORT, ['anrId' => $anrId]); - $anr = $this->anrTable->findById($anrId); + ->getLatestTaskByNameWithParam(CronTask::NAME_INSTANCE_IMPORT, ['anrId' => $anr->getId()]); if ($importCronTask !== null && !$anr->isActive()) { $anr->setStatus(AnrSuperClass::STATUS_ACTIVE); - $this->anrTable->saveEntity($anr, false); + $this->anrTable->save($anr, false); $this->cronTaskService->terminateCronTask($importCronTask); } } - return new JsonModel(['status' => 'ok']); + return $this->getSuccessfulJsonResponse(); } } diff --git a/src/Import/Controller/ApiAnrObjectsImportController.php b/src/Import/Controller/ApiAnrObjectsImportController.php new file mode 100755 index 00000000..1d3e43af --- /dev/null +++ b/src/Import/Controller/ApiAnrObjectsImportController.php @@ -0,0 +1,73 @@ +getRequest()->getAttribute('anr'); + $filter = $this->params()->fromQuery('filter', ''); + + $objects = $this->objectImportService->getObjectsDataFromCommonDatabase($anr, $filter); + + return $this->getPreparedJsonResponse([ + 'count' => \count($objects), + 'objects' => $objects, + ]); + } + + public function get($id) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + return $this->getPreparedJsonResponse($this->objectImportService->getObjectDataFromCommonDatabase($anr, $id)); + } + + public function create($data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $data['file'] = $this->params()->fromFiles('file'); + if (empty($data['file'])) { + throw new Exception('File is missing.', 412); + } + + [$ids, $errors] = $this->objectImportService->importFromFile($anr, $data); + + return $this->getSuccessfulJsonResponse([ + 'id' => $ids, + 'errors' => $errors, + ]); + } + + public function patch($id, $data) + { + /** @var Anr $anr */ + $anr = $this->getRequest()->getAttribute('anr'); + + $object = $this->objectImportService->importFromCommonDatabase($anr, $id, $data); + + return $this->getSuccessfulJsonResponse(['id' => $object->getUuid()]); + } +} diff --git a/src/Import/Helper/ImportCacheHelper.php b/src/Import/Helper/ImportCacheHelper.php index 07b7409f..baa4ebf0 100644 --- a/src/Import/Helper/ImportCacheHelper.php +++ b/src/Import/Helper/ImportCacheHelper.php @@ -1,52 +1,24 @@ themeTable = $themeTable; - $this->soaCategoryTable = $soaCategoryTable; - } - - public function prepareThemesCacheData(Anr $anr): void + public function isCacheKeySet(string $cacheKey): bool { - if (!isset($this->arrayCache['themes_by_labels'])) { - foreach ($this->themeTable->findByAnr($anr) as $theme) { - $this->addItemToArrayCache('themes_by_labels', $theme, $theme->getLabel($anr->getLanguage())); - } - } + return isset($this->arrayCache[$cacheKey]); } - public function prepareSoaCategoriesCacheData(Anr $anr): void + public function isItemInArrayCache(string $cacheKey, $itemKey): bool { - if (!isset($this->arrayCache['soa_categories_by_ref_and_label'])) { - foreach ($this->soaCategoryTable->findByAnr($anr) as $soaCategory) { - $this->addItemToArrayCache( - 'soa_categories_by_ref_and_label', - $soaCategory, - $soaCategory->getReferential()->getUuid() . '_' . $soaCategory->getLabel($anr->getLanguage()) - ); - } - } + return isset($this->arrayCache[$cacheKey][$itemKey]); } public function addItemToArrayCache(string $cacheKey, $value, $itemKey = null): void @@ -59,7 +31,7 @@ public function addItemToArrayCache(string $cacheKey, $value, $itemKey = null): } /** - * @return mixed + * @return array|null|mixed */ public function getItemFromArrayCache(string $cacheKey, $itemKey = null) { @@ -70,8 +42,15 @@ public function getItemFromArrayCache(string $cacheKey, $itemKey = null) return $this->arrayCache[$cacheKey][$itemKey] ?? null; } - public function cleanArrayCache(): void + /** Sets a single array cache value. */ + public function setArrayCacheValue(string $cacheKey, $value): void + { + $this->arrayCache[$cacheKey] = $value; + } + + /** Returns the array cache value or null if not set. */ + public function getValueFromArrayCache(string $cacheKey) { - $this->arrayCache = []; + return $this->arrayCache[$cacheKey] ?? null; } } diff --git a/src/Import/Processor/AnrInstanceMetadataFieldImportProcessor.php b/src/Import/Processor/AnrInstanceMetadataFieldImportProcessor.php new file mode 100644 index 00000000..c4ffba72 --- /dev/null +++ b/src/Import/Processor/AnrInstanceMetadataFieldImportProcessor.php @@ -0,0 +1,73 @@ +processAnrInstanceMetadataField($anr, $anrInstanceMetadataFieldData); + } + } + + public function processAnrInstanceMetadataField( + Entity\Anr $anr, + array $metadataFieldData + ): Entity\AnrInstanceMetadataField { + $anrInstanceMetadataField = $this->getAnrInstanceMetadataFieldsFromCache($anr, $metadataFieldData['label']); + if ($anrInstanceMetadataField !== null) { + return $anrInstanceMetadataField; + } + + $metadataField = $this->anrInstanceMetadataFieldService->createAnrInstanceMetadataField( + $anr, + $metadataFieldData['label'], + $metadataFieldData['isDeletable'] ?? true, + false + ); + $this->importCacheHelper->addItemToArrayCache( + 'anr_instance_metadata_fields', + $metadataField, + $metadataField->getLabel() + ); + + return $metadataField; + } + + private function getAnrInstanceMetadataFieldsFromCache( + Entity\Anr $anr, + string $label + ): ?Entity\AnrInstanceMetadataField { + if (!$this->importCacheHelper->isCacheKeySet('is_anr_instance_metadata_fields_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_anr_instance_metadata_fields_cache_loaded', true); + /** @var Entity\AnrInstanceMetadataField $anrInstanceMetadataField */ + foreach ($this->anrInstanceMetadataFieldTable->findByAnr($anr) as $anrInstanceMetadataField) { + $this->importCacheHelper->addItemToArrayCache( + 'anr_instance_metadata_fields', + $anrInstanceMetadataField, + $anrInstanceMetadataField->getLabel() + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('anr_instance_metadata_fields', $label); + } +} diff --git a/src/Import/Processor/AnrMethodStepImportProcessor.php b/src/Import/Processor/AnrMethodStepImportProcessor.php new file mode 100644 index 00000000..00d2c8b7 --- /dev/null +++ b/src/Import/Processor/AnrMethodStepImportProcessor.php @@ -0,0 +1,177 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function processAnrMethodStepsData(Entity\Anr $anr, array $methodStepsData): void + { + if (!empty($methodStepsData['questions'])) { + /* The only place where the data is flushed, so has to be called first. */ + $this->processQuestionsData($anr, $methodStepsData); + } + + /* Set method steps checkboxes. */ + if (!empty($methodStepsData['steps'])) { + $anr->setInitAnrContext((int)$methodStepsData['steps']['initAnrContext']) + ->setInitEvalContext((int)$methodStepsData['steps']['initEvalContext']) + ->setInitRiskContext((int)$methodStepsData['steps']['initRiskContext']) + ->setInitDefContext((int)$methodStepsData['steps']['initDefContext']) + ->setModelImpacts((int)$methodStepsData['steps']['modelImpacts']) + ->setModelSummary((int)$methodStepsData['steps']['modelSummary']) + ->setEvalRisks((int)$methodStepsData['steps']['evalRisks']) + ->setEvalPlanRisks((int)$methodStepsData['steps']['evalPlanRisks']) + ->setManageRisks((int)$methodStepsData['steps']['manageRisks']) + ->setUpdater($this->connectedUser->getEmail()); + $this->anrTable->save($anr, false); + } + + /* Set data of text-boxes. */ + if (!empty($methodStepsData['data'])) { + $anr->setContextAnaRisk($methodStepsData['data']['contextAnaRisk'] ?? '') + ->setContextGestRisk($methodStepsData['data']['contextGestRisk'] ?? '') + ->setSynthThreat($methodStepsData['data']['synthThreat'] ?? '') + ->setSynthAct($methodStepsData['data']['synthAct'] ?? '') + ->setUpdater($this->connectedUser->getEmail()); + $this->anrTable->save($anr, false); + } + + /* Recreate the generated deliveries reports. */ + if (!empty($methodStepsData['deliveries'])) { + foreach ($methodStepsData['deliveries'] as $deliveryData) { + $delivery = (new Entity\Delivery()) + ->setAnr($anr) + ->setName($deliveryData['name']) + ->setDocType($deliveryData['typedoc']) + ->setVersion($deliveryData['version']) + ->setStatus($deliveryData['status']) + ->setClassification($deliveryData['classification']) + ->setRespCustomer($deliveryData['respCustomer']) + ->setResponsibleManager($deliveryData['responsibleManager'] ?? $deliveryData['respSmile']) + ->setSummaryEvalRisk($deliveryData['summaryEvalRisk']) + ->setCreator($this->connectedUser->getEmail()); + $this->deliveryTable->save($delivery, false); + } + } + + if (!empty($methodStepsData['interviews'])) { + $this->processInterviewsData($anr, $methodStepsData['interviews']); + } + + if (!empty($methodStepsData['thresholds'])) { + $this->processThresholdsData($anr, $methodStepsData['thresholds']); + } + + /* Process the evaluation of threats. */ + if (!empty($methodStepsData['threats'])) { + $this->threatImportProcessor->processThreatsData($anr, $methodStepsData['threats']); + } + } + + public function processThresholdsData(Entity\Anr $anr, array $thresholdsData): void + { + $anr->setSeuil1((int)$thresholdsData['seuil1']) + ->setSeuil2((int)$thresholdsData['seuil2']) + ->setSeuilRolf1((int)$thresholdsData['seuilRolf1']) + ->setSeuilRolf2((int)$thresholdsData['seuilRolf2']) + ->setUpdater($this->connectedUser->getEmail()); + $this->anrTable->save($anr, false); + } + + public function processInterviewsData(Entity\Anr $anr, array $interviewsData): void + { + foreach ($interviewsData as $interviewData) { + $newInterview = (new Entity\Interview()) + ->setAnr($anr) + ->setDate($interviewData['date']) + ->setContent($interviewData['content']) + ->setService($interviewData['service']) + ->setCreator($this->connectedUser->getEmail()); + $this->interviewTable->saveEntity($newInterview, false); + } + } + + private function processQuestionsData(Entity\Anr $anr, array $methodStepsData): void + { + foreach ($this->questionTable->findByAnr($anr) as $question) { + $this->questionTable->deleteEntity($question, false); + } + + foreach ($methodStepsData['questions'] as $position => $questionData) { + /* In the new data structure there is only "label" field set. */ + if (isset($questionData['label'])) { + $questionData['label' . $anr->getLanguage()] = $questionData['label']; + } + $question = (new Entity\Question()) + ->setAnr($anr) + ->setLabels($questionData) + ->setMode($questionData['mode']) + ->setIsMultiChoice($questionData['isMultiChoice'] ?? (bool)$questionData['multichoice']) + ->setType($questionData['type']) + ->setResponse((string)$questionData['response']) + ->setPosition($position) + ->setCreator($this->connectedUser->getEmail()); + $this->questionTable->saveEntity($question, false); + + if ($question->isMultiChoice()) { + $choicesOldIdsToNewObjects = []; + /* Support the old structure format, prior v2.13.1 */ + $questionChoicesData = $methodStepsData['questionChoice'] ?? $questionData['questionChoices']; + foreach ($questionChoicesData as $questionChoiceId => $questionChoiceData) { + if (!isset($questionChoiceData['question']) + || $questionChoiceData['question'] === $questionData['id'] + ) { + if (isset($questionChoiceData['label'])) { + $questionChoiceData['label' . $anr->getLanguage()] = $questionChoiceData['label']; + } + $questionChoice = (new Entity\QuestionChoice())->setAnr($anr)->setQuestion($question) + ->setLabels($questionChoiceData)->setPosition($questionChoiceData['position']) + ->setCreator($this->connectedUser->getEmail()); + $this->questionChoiceTable->saveEntity($questionChoice, false); + $choicesOldIdsToNewObjects[$questionChoiceData['id'] ?? $questionChoiceId] = $questionChoice; + } + } + $response = trim($question->getResponse(), '[]'); + if ($response !== '') { + /* The flush is necessary as responses are stored as array of IDs from the exported DB. + TODO: refactor the responses saving in a separate table and avoid the flush operation here. */ + $this->questionChoiceTable->getDb()->flush(); + $originQuestionChoicesIds = explode(',', $response); + $questionChoicesIds = []; + foreach ($originQuestionChoicesIds as $originQuestionChoicesId) { + if (isset($choicesOldIdsToNewObjects[$originQuestionChoicesId])) { + $questionChoicesIds[] = $choicesOldIdsToNewObjects[$originQuestionChoicesId]->getId(); + } + } + $question->setResponse('[' . implode(',', $questionChoicesIds) . ']'); + $this->questionTable->save($question, false); + } + } + } + } +} diff --git a/src/Import/Processor/AssetImportProcessor.php b/src/Import/Processor/AssetImportProcessor.php new file mode 100644 index 00000000..6a3e04a3 --- /dev/null +++ b/src/Import/Processor/AssetImportProcessor.php @@ -0,0 +1,74 @@ +processAssetData($anr, $assetData); + } + } + + public function processAssetData(Entity\Anr $anr, array $assetData): Entity\Asset + { + $asset = $this->getAssetFromCache($anr, $assetData['uuid']); + if ($asset === null) { + /* The code should be unique. */ + if ($this->importCacheHelper->isItemInArrayCache('assets_codes', $assetData['code'])) { + $assetData['code'] .= '-' . time(); + } + + /* In the new data structure there is only "label" field set. */ + if (isset($assetData['label'])) { + $assetData['label' . $anr->getLanguage()] = $assetData['label']; + } + if (isset($assetData['description'])) { + $assetData['description' . $anr->getLanguage()] = $assetData['description']; + } + + $asset = $this->anrAssetService->create($anr, $assetData, false); + $this->importCacheHelper->addItemToArrayCache('assets_by_uuid', $asset, $asset->getUuid()); + } + + /* In case if the process is called from the object then process information risks data. */ + if (!empty($assetData['informationRisks'])) { + $this->informationRiskImportProcessor->processInformationRisksData($anr, $assetData['informationRisks']); + } + + return $asset; + } + + public function getAssetFromCache(Entity\Anr $anr, string $uuid): ?Entity\Asset + { + if (!$this->importCacheHelper->isCacheKeySet('is_assets_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_assets_cache_loaded', true); + /** @var Entity\Asset $asset */ + foreach ($this->assetTable->findByAnr($anr) as $asset) { + $this->importCacheHelper->addItemToArrayCache('assets_by_uuid', $asset, $asset->getUuid()); + $this->importCacheHelper->addItemToArrayCache('assets_codes', $asset->getCode(), $asset->getCode()); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('assets_by_uuid', $uuid); + } +} diff --git a/src/Import/Processor/InformationRiskImportProcessor.php b/src/Import/Processor/InformationRiskImportProcessor.php new file mode 100644 index 00000000..508d2924 --- /dev/null +++ b/src/Import/Processor/InformationRiskImportProcessor.php @@ -0,0 +1,103 @@ +processInformationRiskData($anr, $informationRiskData); + } + } + + public function processInformationRiskData(Entity\Anr $anr, array $informationRiskData): Entity\Amv + { + $informationRisk = $this->getInformationRiskFromCache($anr, $informationRiskData['uuid']); + if ($informationRisk === null) { + $asset = $this->assetImportProcessor->processAssetData($anr, $informationRiskData['asset']); + $threat = $this->threatImportProcessor->processThreatData($anr, $informationRiskData['threat']); + $vulnerability = $this->vulnerabilityImportProcessor + ->processVulnerabilityData($anr, $informationRiskData['vulnerability']); + + /* Prepare the max positions per asset as the objects are not saved in the DB. */ + if (!isset($this->maxPositionsPerAsset[$asset->getUuid()])) { + $this->maxPositionsPerAsset[$asset->getUuid()] = $this->amvTable->findMaxPosition([ + 'anr' => $anr, + 'asset' => [ + 'uuid' => $asset->getUuid(), + 'anr' => $anr, + ], + ]); + } + + $informationRisk = $this->anrAmvService->createAmvFromPreparedData($anr, $asset, $threat, $vulnerability, [ + 'uuid' => $informationRiskData['uuid'], + 'status' => $informationRiskData['status'], + 'setOnlyExactPosition' => true, + 'position' => ++$this->maxPositionsPerAsset[$asset->getUuid()], + ], false, false); + + $this->importCacheHelper + ->addItemToArrayCache('amvs_by_uuid', $informationRisk, $informationRisk->getUuid()); + } + + $saveInformationRisk = false; + foreach ($informationRiskData['measures'] ?? [] as $measureData) { + $measure = $this->referentialImportProcessor->getMeasureFromCache($anr, $measureData['uuid']); + if ($measure === null && !empty($measureData['referential'])) { + $referential = $this->referentialImportProcessor->processReferentialData( + $anr, + $measureData['referential'] + ); + $measure = $this->referentialImportProcessor->processMeasureData($anr, $referential, $measureData); + } + if ($measure !== null) { + $informationRisk->addMeasure($measure); + $saveInformationRisk = true; + } + } + + if ($saveInformationRisk) { + $this->amvTable->save($informationRisk, false); + } + + return $informationRisk; + } + + private function getInformationRiskFromCache(Entity\Anr $anr, string $uuid): ?Entity\Amv + { + if (!$this->importCacheHelper->isCacheKeySet('is_amvs_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_amvs_cache_loaded', true); + /** @var Entity\Amv $amv */ + foreach ($this->amvTable->findByAnr($anr) as $amv) { + $this->importCacheHelper->addItemToArrayCache('amvs_by_uuid', $amv, $amv->getUuid()); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('amvs_by_uuid', $uuid); + } +} diff --git a/src/Import/Processor/InstanceConsequenceImportProcessor.php b/src/Import/Processor/InstanceConsequenceImportProcessor.php new file mode 100644 index 00000000..55f93b27 --- /dev/null +++ b/src/Import/Processor/InstanceConsequenceImportProcessor.php @@ -0,0 +1,133 @@ +importCacheHelper->getValueFromArrayCache('with_eval')) { + foreach ($instanceConsequencesData as $instanceConsequenceData) { + $this->processInstanceConsequenceData($instance, $instanceConsequenceData); + } + } elseif ($siblingInstance === null) { + $this->createInstanceConsequencesBasedOnExistingImpactTypes($instance); + } else { + $this->createInstanceConsequencesBasedOnSiblingInstance($instance, $siblingInstance); + } + } + + public function processInstanceConsequenceData( + Entity\Instance $instance, + array $instanceConsequenceData + ): ?Entity\InstanceConsequence { + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); + $scaleImpactType = $this->scaleImportProcessor + ->getScaleImpactTypeFromCacheByLabel($anr, $instanceConsequenceData['scaleImpactType']['label']); + if ($scaleImpactType === null) { + $scaleType = $instanceConsequenceData['scaleImpactType']['scale']['type'] ?? null; + if ($scaleType === null) { + return null; + } + $scale = $this->scaleImportProcessor->getCurrentScaleFromCacheByType($scaleType); + if ($scale === null) { + return null; + } + + $scaleImpactTypesNumber = \count($this->scaleImportProcessor->getScalesImpactTypesFromCache($anr)); + $scaleImpactType = $this->scaleImportProcessor->createNewScaleImpactType( + $anr, + $scale, + $instanceConsequenceData['scaleImpactType'], + $scaleImpactTypesNumber + ); + } + + /* For the instances import the values have to be converted to local scales. */ + if ($this->importCacheHelper + ->getValueFromArrayCache('import_type') === InstanceImportService::IMPORT_TYPE_INSTANCE + ) { + $this->convertInstanceConsequencesEvaluations($instanceConsequenceData); + } + + return $this->anrInstanceConsequenceService->createInstanceConsequence( + $instance, + $scaleImpactType, + (bool)$instanceConsequenceData['isHidden'], + $instanceConsequenceData, + false + ); + } + + public function createInstanceConsequencesBasedOnExistingImpactTypes(Entity\Instance $instance): void + { + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); + foreach ($this->scaleImportProcessor->getScalesImpactTypesFromCache($anr) as $scaleImpactType) { + $this->anrInstanceConsequenceService + ->createInstanceConsequence($instance, $scaleImpactType, $scaleImpactType->isHidden()); + } + } + + public function createInstanceConsequencesBasedOnSiblingInstance( + Entity\Instance $instance, + Entity\Instance $siblingInstance + ): void { + foreach ($siblingInstance->getInstanceConsequences() as $instanceConsequence) { + /** @var Entity\ScaleImpactType $scalesImpactType */ + $scalesImpactType = $instanceConsequence->getScaleImpactType(); + $this->anrInstanceConsequenceService->createInstanceConsequence( + $instance, + $scalesImpactType, + $instanceConsequence->isHidden(), + [ + 'confidentiality' => $instanceConsequence->getConfidentiality(), + 'integrity' => $instanceConsequence->getIntegrity(), + 'availability' => $instanceConsequence->getAvailability(), + ] + ); + } + } + + private function convertInstanceConsequencesEvaluations(array &$instanceData): void + { + $currentScaleRange = $this->importCacheHelper + ->getItemFromArrayCache('current_scales_data_by_type')[ScaleSuperClass::TYPE_IMPACT]; + $externalScaleRange = $this->importCacheHelper + ->getItemFromArrayCache('external_scales_data_by_type')[ScaleSuperClass::TYPE_IMPACT]; + foreach (['confidentiality', 'integrity', 'availability'] as $propertyName) { + $instanceData[$propertyName] = $this->convertValueWithinNewScalesRange( + $instanceData[$propertyName], + $externalScaleRange['min'], + $externalScaleRange['max'], + $currentScaleRange['min'], + $currentScaleRange['max'], + ); + } + } +} diff --git a/src/Import/Processor/InstanceImportProcessor.php b/src/Import/Processor/InstanceImportProcessor.php new file mode 100644 index 00000000..4b1a2dbb --- /dev/null +++ b/src/Import/Processor/InstanceImportProcessor.php @@ -0,0 +1,259 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + /** + * @return Entity\Instance[] List of the created root instances. + */ + public function processInstancesData( + Entity\Anr $anr, + array $instancesData, + ?Entity\Instance $parentInstance, + string $importMode + ): array { + $maxPositionInsideOfParentInstance = 0; + /* The query to get the max position is executed only if the parent instances is set and stored in the DB. */ + if ($parentInstance !== null && $parentInstance->getId() !== null) { + $maxPositionInsideOfParentInstance = $this->instanceTable->findMaxPosition( + $parentInstance->getImplicitPositionRelationsValues() + ); + } + $instances = []; + foreach ($instancesData as $instanceData) { + $instanceData['position'] += $maxPositionInsideOfParentInstance++; + $instanceData['setOnlyExactPosition'] = true; + $instances[] = $this->processInstanceData($anr, $instanceData, $parentInstance, $importMode); + } + + return $instances; + } + + /** The method is called as a starting point of the root instances import and should not be called recursively. */ + public function processInstanceData( + Entity\Anr $anr, + array $instanceData, + ?Entity\Instance $parentInstance, + string $importMode + ): Entity\Instance { + $objectCategory = null; + if (isset($instanceData['object']['category'])) { + $objectCategory = $this->objectCategoryImportProcessor + ->processObjectCategoryData($anr, $instanceData['object']['category'], $importMode); + } + $instanceData['object'] = $this->objectImportProcessor + ->processObjectData($anr, $objectCategory, $instanceData['object'], $importMode); + $instanceData['parent'] = $parentInstance; + + /* For the instances import the values have to be converted to local scales. */ + if ($this->importCacheHelper->getValueFromArrayCache('with_eval') && $this->importCacheHelper + ->getValueFromArrayCache('import_type') === InstanceImportService::IMPORT_TYPE_INSTANCE + ) { + $this->convertInstanceEvaluations($instanceData); + } + $instance = $this->instanceService->createInstance($anr, $instanceData, $parentInstance === null, false); + $this->prepareAndProcessInstanceConsequencesData($instance, $instanceData['instancesConsequences']); + $instance->updateImpactBasedOnConsequences(); + /* In case if there is a parent instance, the scales impacts could be adjusted, if they are not set directly. */ + if ($parentInstance !== null) { + $instance->refreshInheritedImpact(); + } + + $siblingInstances = []; + if (!$this->importCacheHelper->getValueFromArrayCache('with_eval') && $instance->getObject()->isScopeGlobal()) { + $siblingInstances = $this->getGlobalObjectInstancesFromCache($anr, $instance->getObject()->getUuid()); + } + $this->instanceRiskImportProcessor + ->processInstanceRisksData($instance, $siblingInstances, $instanceData['instanceRisks']); + + $this->operationalInstanceRiskImportProcessor + ->processOperationalInstanceRisksData($anr, $instance, $instanceData['operationalInstanceRisks']); + + $this->processInstanceMetadata($anr, $instance, $instanceData['instanceMetadata']); + + if (!empty($instanceData['children'])) { + $this->processInstancesData($anr, $instanceData['children'], $instance, $importMode); + } + + return $instance; + } + + public function processInstanceMetadata( + Entity\Anr $anr, + Entity\Instance $instance, + array $instanceMetadataData + ): void { + foreach ($instanceMetadataData as $metadataDatum) { + $metadataField = $this->anrInstanceMetadataFieldImportProcessor->processAnrInstanceMetadataField($anr, [ + 'label' => $metadataDatum['anrInstanceMetadataField']['label'] ?? $metadataDatum['label'], + 'isDeletable' => true, + ]); + + $instanceMetadata = $instance->getInstanceMetadataByMetadataFieldLink($metadataField); + if ($instanceMetadata === null) { + $instanceMetadata = (new Entity\InstanceMetadata()) + ->setInstance($instance) + ->setAnrInstanceMetadataField($metadataField) + ->setComment($metadataDatum['comment']) + ->setCreator($this->connectedUser->getEmail()); + $this->instanceMetadataTable->save($instanceMetadata, false); + + $this->applyInstanceMetadataToSiblings($anr, $instance, $instanceMetadata); + } elseif ($instanceMetadata->getComment() !== $metadataDatum['comment']) { + $instanceMetadata->setComment($metadataDatum['comment'])->setUpdater($this->connectedUser->getEmail()); + $this->instanceMetadataTable->save($instanceMetadata, false); + } + } + + $this->updateInstanceMetadataFromSiblings($anr, $instance); + } + + /** A wrapper method to help of processing the instance consequences data. */ + public function prepareAndProcessInstanceConsequencesData( + Entity\Instance $instance, + array $instanceConsequencesData + ): void { + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); + /* When the importing data are without evaluation and the object is global + the evaluations are taken from a sibling. */ + $siblingInstance = null; + if (!$this->importCacheHelper->getValueFromArrayCache('with_eval') && $instance->getObject()->isScopeGlobal()) { + $siblingInstances = $this->getGlobalObjectInstancesFromCache($anr, $instance->getObject()->getUuid()); + $siblingInstance = $siblingInstances[0] ?? null; + } + + $this->instanceConsequenceImportProcessor + ->processInstanceConsequencesData($instance, $instanceConsequencesData, $siblingInstance); + } + + /** + * Applies the newly created instance metadata to the others global sibling instances. + */ + private function applyInstanceMetadataToSiblings( + Entity\Anr $anr, + Entity\Instance $instance, + Entity\InstanceMetadata $instanceMetadata + ): void { + if ($instance->getObject()->isScopeGlobal()) { + $instanceSiblings = $this->getGlobalObjectInstancesFromCache($anr, $instance->getObject()->getUuid()); + foreach ($instanceSiblings as $instanceSibling) { + $instanceMetadataOfSibling = $instanceSibling->getInstanceMetadataByMetadataFieldLink( + $instanceMetadata->getAnrInstanceMetadataField() + ); + if ($instanceMetadataOfSibling === null) { + $instanceMetadataOfSibling = (new Entity\InstanceMetadata()) + ->setInstance($instanceSibling) + ->setAnrInstanceMetadataField($instanceMetadata->getAnrInstanceMetadataField()) + ->setComment($instanceMetadata->getComment()) + ->setCreator($this->connectedUser->getEmail()); + $this->instanceMetadataTable->save($instanceMetadataOfSibling, false); + } + } + } + } + + /** + * Updates the instance metadata from the others global sibling instances. + */ + private function updateInstanceMetadataFromSiblings(Entity\Anr $anr, Entity\Instance $instance): void + { + if ($instance->getObject()->isScopeGlobal()) { + $instanceSibling = current( + $this->getGlobalObjectInstancesFromCache($anr, $instance->getObject()->getUuid()) + ); + if ($instanceSibling !== false) { + foreach ($instanceSibling->getInstanceMetadata() as $instanceMetadataOfSibling) { + $instanceMetadata = $instance->getInstanceMetadataByMetadataFieldLink( + $instanceMetadataOfSibling->getAnrInstanceMetadataField() + ); + if ($instanceMetadata === null) { + $instanceMetadata = (new Entity\InstanceMetadata()) + ->setInstance($instance) + ->setAnrInstanceMetadataField($instanceMetadataOfSibling->getAnrInstanceMetadataField()) + ->setComment($instanceMetadataOfSibling->getComment()) + ->setCreator($this->connectedUser->getEmail()); + $this->instanceMetadataTable->save($instanceMetadata, false); + } + } + } + } + } + + /** + * @return Entity\Instance[] + */ + private function getGlobalObjectInstancesFromCache(Entity\Anr $anr, string $objectUuid): array + { + if (!$this->importCacheHelper->isCacheKeySet('is_global_instances_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_global_instances_cache_loaded', true); + foreach ($this->monarcObjectTable->findGlobalObjectsByAnr($anr) as $object) { + $instances = []; + foreach ($object->getInstances() as $instance) { + $instances[] = $instance; + } + $this->importCacheHelper->addItemToArrayCache( + 'global_instances_by_object_uuids', + $instances, + $object->getUuid() + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('global_instances_by_object_uuids', $objectUuid) ?? []; + } + + private function convertInstanceEvaluations(array &$instanceData): void + { + $currentScaleRange = $this->importCacheHelper + ->getItemFromArrayCache('current_scales_data_by_type')[ScaleSuperClass::TYPE_IMPACT]; + $externalScaleRange = $this->importCacheHelper + ->getItemFromArrayCache('external_scales_data_by_type')[ScaleSuperClass::TYPE_IMPACT]; + foreach (['confidentiality', 'integrity', 'availability'] as $propertyName) { + $instanceData[$propertyName] = $this->convertValueWithinNewScalesRange( + $instanceData[$propertyName], + $externalScaleRange['min'], + $externalScaleRange['max'], + $currentScaleRange['min'], + $currentScaleRange['max'], + ); + } + } +} diff --git a/src/Import/Processor/InstanceRiskImportProcessor.php b/src/Import/Processor/InstanceRiskImportProcessor.php new file mode 100644 index 00000000..5047da6c --- /dev/null +++ b/src/Import/Processor/InstanceRiskImportProcessor.php @@ -0,0 +1,245 @@ +processInstanceRiskData($instance, $instanceRiskData); + } + if (!empty($siblingInstances)) { + /* Match the created instance risks with sibling instances' ones. */ + $this->matchCreatedInstanceRisksWithSiblingInstances($instance, $siblingInstances); + } + } + + private function processInstanceRiskData(Entity\Instance $instance, array $instanceRiskData): Entity\InstanceRisk + { + /** @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 + ->processVulnerabilityData($anr, $instanceRiskData['vulnerability']); + } + + $instanceRisk = $this->anrInstanceRiskService + ->createInstanceRisk($instance, $amv, null, $threat, $vulnerability); + + foreach ($instanceRiskData['recommendations'] as $recommendationData) { + $recommendationSet = $this->recommendationImportProcessor + ->processRecommendationSetData($anr, $recommendationData['recommendationSet']); + $recommendation = $this->recommendationImportProcessor + ->processRecommendationData($recommendationSet, $recommendationData); + $this->anrRecommendationRiskService->createRecommendationRisk( + $recommendation, + $instanceRisk, + $recommendationData['commentAfter'] ?? '', + false + ); + } + + if ($this->importCacheHelper->getValueFromArrayCache('with_eval')) { + /* For the instances import the values have to be converted to local scales. */ + if ($this->importCacheHelper + ->getValueFromArrayCache('import_type') === InstanceImportService::IMPORT_TYPE_INSTANCE + ) { + $this->convertInstanceRiskEvaluations($instanceRiskData); + } + + $instanceRisk + ->setRiskConfidentiality($instanceRiskData['riskConfidentiality']) + ->setRiskIntegrity($instanceRiskData['riskIntegrity']) + ->setRiskAvailability($instanceRiskData['riskAvailability']) + ->setThreatRate($instanceRiskData['threatRate']) + ->setVulnerabilityRate($instanceRiskData['vulnerabilityRate']) + ->setReductionAmount($instanceRiskData['reductionAmount']) + ->setCacheMaxRisk($instanceRiskData['cacheMaxRisk']) + ->setCacheTargetedRisk($instanceRiskData['cacheTargetedRisk']) + ->setKindOfMeasure($instanceRiskData['kindOfMeasure']) + ->setComment($instanceRiskData['comment'] ?? '') + ->setCommentAfter($instanceRiskData['commentAfter'] ?? '') + ->setIsThreatRateNotSetOrModifiedExternally( + (bool)$instanceRiskData['isThreatRateNotSetOrModifiedExternally'] + ) + ->setContext($instanceRiskData['context'] ?? ''); + if (!empty($instanceRiskData['riskOwner'])) { + $this->instanceRiskOwnerService + ->processRiskOwnerNameAndAssign($instanceRiskData['riskOwner'], $instanceRisk); + } + } + + $this->anrInstanceRiskService->recalculateRiskRates($instanceRisk); + + $this->instanceRiskTable->save($instanceRisk, false); + + return $instanceRisk; + } + + /** + * @param Entity\Instance[] $siblingInstances + */ + private function matchCreatedInstanceRisksWithSiblingInstances( + Entity\Instance $instance, + array $siblingInstances + ): void { + $createdRiskKeys = []; + $siblingRiskKeys = []; + $withEval = $this->importCacheHelper->getValueFromArrayCache('with_eval'); + foreach ($siblingInstances as $siblingInstance) { + /** @var Entity\InstanceRisk $createdInstanceRisk */ + foreach ($instance->getInstanceRisks() as $createdInstanceRisk) { + $createdRiskKey = $createdInstanceRisk->getAsset()->getUuid() + . $createdInstanceRisk->getThreat()->getUuid() + . $createdInstanceRisk->getVulnerability()->getUuid(); + $createdRiskKeys[$createdRiskKey] = $createdInstanceRisk; + $isRiskMatched = false; + foreach ($siblingInstance->getInstanceRisks() as $siblingInstanceRisk) { + $siblingRiskKey = $siblingInstanceRisk->getAsset()->getUuid() + . $siblingInstanceRisk->getThreat()->getUuid() + . $siblingInstanceRisk->getVulnerability()->getUuid(); + $siblingRiskKeys[$siblingRiskKey][] = $siblingInstanceRisk; + if ($createdRiskKey === $siblingRiskKey) { + if ($withEval) { + /* Apply the evaluations to the sibling instance's risk. */ + $this->applyRiskDataToItsSibling($createdInstanceRisk, $siblingInstanceRisk); + } else { + /* Apply not evaluated data to the created risk from the sibling one. */ + $this->applyRiskDataToItsSibling($siblingInstanceRisk, $createdInstanceRisk); + } + $isRiskMatched = true; + } + } + /* If the instance risk is not presented then create from the original one */ + if (!$isRiskMatched) { + /** @var ?Entity\Amv $amv */ + $amv = $createdInstanceRisk->getAmv(); + $newSiblingInstanceRisk = $this->anrInstanceRiskService + ->createInstanceRisk($siblingInstance, $amv, $createdInstanceRisk); + foreach ($createdInstanceRisk->getRecommendationRisks() as $createdRecommendationRisk) { + $newSiblingRecommendationRisk = $this->anrRecommendationRiskService->createRecommendationRisk( + $createdRecommendationRisk->getRecommendation(), + $newSiblingInstanceRisk, + $createdRecommendationRisk->getCommentAfter() + ); + $newSiblingInstanceRisk->addRecommendationRisk($newSiblingRecommendationRisk); + } + $this->instanceRiskTable->save($newSiblingInstanceRisk, false); + } + } + } + /* Remove not matched instance risks. */ + /** @var Entity\InstanceRisk[] $siblingInstanceRisksToRemove */ + foreach (array_diff_key($siblingRiskKeys, $createdRiskKeys) as $siblingInstanceRisksToRemove) { + foreach ($siblingInstanceRisksToRemove as $siblingInstanceRiskToRemove) { + $siblingInstanceRiskToRemove->getInstance()->removeInstanceRisk($siblingInstanceRiskToRemove); + $this->instanceRiskTable->remove($siblingInstanceRiskToRemove, false); + } + } + } + + private function applyRiskDataToItsSibling( + Entity\InstanceRisk $fromInstanceRisk, + Entity\InstanceRisk $toInstanceRisk + ): void { + $toInstanceRisk + ->setThreatRate($fromInstanceRisk->getThreatRate()) + ->setVulnerabilityRate($fromInstanceRisk->getVulnerabilityRate()) + ->setKindOfMeasure($fromInstanceRisk->getKindOfMeasure()) + ->setReductionAmount($fromInstanceRisk->getReductionAmount()) + ->setRiskConfidentiality($fromInstanceRisk->getRiskConfidentiality()) + ->setRiskIntegrity($fromInstanceRisk->getRiskIntegrity()) + ->setRiskAvailability($fromInstanceRisk->getRiskAvailability()) + ->setCacheMaxRisk($fromInstanceRisk->getCacheMaxRisk()) + ->setCacheTargetedRisk($fromInstanceRisk->getCacheTargetedRisk()) + ->setSpecific((int)$fromInstanceRisk->isSpecific()) + ->setAmv($fromInstanceRisk->getAmv()) + ->setContext($fromInstanceRisk->getContext()) + ->setInstanceRiskOwner($fromInstanceRisk->getInstanceRiskOwner()); + $this->anrInstanceRiskService->recalculateRiskRates($toInstanceRisk); + + $this->instanceRiskTable->save($toInstanceRisk, false); + } + + private function convertInstanceRiskEvaluations(array &$instanceRiskData): void + { + $currentScalesRanges = $this->importCacheHelper->getItemFromArrayCache('current_scales_data_by_type'); + $externalScalesRanges = $this->importCacheHelper->getItemFromArrayCache('external_scales_data_by_type'); + foreach (['riskConfidentiality', 'riskIntegrity', 'riskAvailability'] as $propertyName) { + $instanceRiskData[$propertyName] = $this->convertValueWithinNewScalesRange( + $instanceRiskData[$propertyName], + $externalScalesRanges[ScaleSuperClass::TYPE_IMPACT]['min'], + $externalScalesRanges[ScaleSuperClass::TYPE_IMPACT]['max'], + $currentScalesRanges[ScaleSuperClass::TYPE_IMPACT]['min'], + $currentScalesRanges[ScaleSuperClass::TYPE_IMPACT]['max'], + ); + } + $instanceRiskData['threatRate'] = $this->convertValueWithinNewScalesRange( + $instanceRiskData['threatRate'], + $externalScalesRanges[ScaleSuperClass::TYPE_THREAT]['min'], + $externalScalesRanges[ScaleSuperClass::TYPE_THREAT]['max'], + $currentScalesRanges[ScaleSuperClass::TYPE_THREAT]['min'], + $currentScalesRanges[ScaleSuperClass::TYPE_THREAT]['max'], + ); + $previousVulnerabilityRate = $instanceRiskData['vulnerabilityRate']; + $instanceRiskData['vulnerabilityRate'] = $this->convertValueWithinNewScalesRange( + $instanceRiskData['vulnerabilityRate'], + $externalScalesRanges[ScaleSuperClass::TYPE_VULNERABILITY]['min'], + $externalScalesRanges[ScaleSuperClass::TYPE_VULNERABILITY]['max'], + $currentScalesRanges[ScaleSuperClass::TYPE_VULNERABILITY]['min'], + $currentScalesRanges[ScaleSuperClass::TYPE_VULNERABILITY]['max'], + ); + $instanceRiskData['reductionAmount'] = $this->convertValueWithinNewScalesRange( + $instanceRiskData['reductionAmount'], + 0, + $previousVulnerabilityRate, + 0, + $instanceRiskData['vulnerabilityRate'], + 0 + ); + } +} diff --git a/src/Import/Processor/ObjectCategoryImportProcessor.php b/src/Import/Processor/ObjectCategoryImportProcessor.php new file mode 100644 index 00000000..0fdeb52e --- /dev/null +++ b/src/Import/Processor/ObjectCategoryImportProcessor.php @@ -0,0 +1,126 @@ +processObjectCategoryData($anr, $categoryData, $importMode); + } + } + + public function processObjectCategoryData( + Entity\Anr $anr, + array $objectCategoryData, + string $importMode + ): Entity\ObjectCategory { + $parentCategory = null; + $labelKey = 'label' . $anr->getLanguage(); + if (!empty($objectCategoryData['parent']) && $objectCategoryData['parent'] instanceof Entity\ObjectCategory) { + $parentCategory = $objectCategoryData['parent']; + } elseif (isset($objectCategoryData['parent']['label']) || isset($objectCategoryData['parent'][$labelKey])) { + $parentCategory = $this->processObjectCategoryData($anr, $objectCategoryData['parent'], $importMode); + $objectCategoryData['parent'] = $parentCategory; + } + + $parentCategoryLabel = ''; + if ($parentCategory !== null) { + $parentCategoryLabel = $parentCategory->getLabel($anr->getLanguage()); + } + + /* In the new data structure there is only "label" field set. */ + if (isset($objectCategoryData['label'])) { + $objectCategoryData[$labelKey] = $objectCategoryData['label']; + } + + /* If parents are different, a new category is created anyway. */ + $objectCategory = $this + ->getObjectCategoryFromCacheByLabel($anr, $objectCategoryData[$labelKey] . $parentCategoryLabel); + + if ($objectCategory === null) { + /* 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. */ + $this->maxPositionPerCategory[$parentCategoryLabel] = 0; + if ($parentCategory === null || $parentCategory->getId() !== null) { + $this->maxPositionPerCategory[$parentCategoryLabel] = $this->objectCategoryTable + ->findMaxPositionByAnrAndParent($anr, $parentCategory); + } + } + $objectCategoryData['position'] = ++$this->maxPositionPerCategory[$parentCategoryLabel]; + $objectCategoryData['setOnlyExactPosition'] = true; + + $objectCategory = $this->anrObjectCategoryService->create($anr, $objectCategoryData, false); + /* Adds the parent category label to the item key to avoid its comparison in the children's process. */ + $this->importCacheHelper->addItemToArrayCache( + 'object_categories_by_label', + $objectCategory, + $objectCategory->getLabel($anr->getLanguage()) . $parentCategoryLabel + ); + } + + if (!empty($objectCategoryData['objects'])) { + $this->objectImportProcessor + ->processObjectsData($anr, $objectCategory, $objectCategoryData['objects'], $importMode); + } + if (!empty($objectCategoryData['children'])) { + foreach ($objectCategoryData['children'] as $childObjectCategoryData) { + $childObjectCategoryData['parent'] = $objectCategory; + $this->processObjectCategoryData($anr, $childObjectCategoryData, $importMode); + } + } + + return $objectCategory; + } + + /* The categories cache's items keys are based on their labels + parent's labels if not root. */ + private function getObjectCategoryFromCacheByLabel( + Entity\Anr $anr, + string $categoryAndItsParentLabels + ): ?Entity\ObjectCategory { + if (!$this->importCacheHelper->isCacheKeySet('is_object_categories_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_object_categories_cache_loaded', true); + $languageIndex = $anr->getLanguage(); + /** @var Entity\ObjectCategory $objectCategory */ + foreach ($this->objectCategoryTable->findByAnr($anr) as $objectCategory) { + $parentCategoryLabel = ''; + if ($objectCategory->getParent() !== null) { + $parentCategoryLabel = $objectCategory->getParent()->getLabel($languageIndex); + } + $this->importCacheHelper->addItemToArrayCache( + 'object_categories_by_label', + $objectCategory, + $objectCategory->getLabel($languageIndex) . $parentCategoryLabel + ); + } + } + + return $this->importCacheHelper + ->getItemFromArrayCache('object_categories_by_label', $categoryAndItsParentLabels); + } +} diff --git a/src/Import/Processor/ObjectImportProcessor.php b/src/Import/Processor/ObjectImportProcessor.php new file mode 100644 index 00000000..26cf5259 --- /dev/null +++ b/src/Import/Processor/ObjectImportProcessor.php @@ -0,0 +1,271 @@ +processObjectData($anr, $objectCategory, $objectData, $importMode); + } + } + + public function processObjectData( + Entity\Anr $anr, + ?Entity\ObjectCategory $objectCategory, + array $objectData, + string $importMode + ): Entity\MonarcObject { + /* Only processed objects are stored under the cache key 'processed_objects_by_old_uuids'. */ + if ($this->importCacheHelper->isItemInArrayCache('processed_objects_by_old_uuids', $objectData['uuid'])) { + return $this->importCacheHelper + ->getItemFromArrayCache('processed_objects_by_old_uuids', $objectData['uuid']); + } + + $objectScope = (int)$objectData['scope']; + $nameFiledKey = 'name' . $anr->getLanguage(); + $object = null; + /* In the new data structure there is only "name" field set. */ + if (isset($objectData['name'])) { + $objectData[$nameFiledKey] = $objectData['name']; + } + if ($objectScope === ObjectSuperClass::SCOPE_LOCAL || ( + $objectScope === ObjectSuperClass::SCOPE_GLOBAL && $importMode === ObjectImportService::IMPORT_MODE_MERGE + )) { + $object = $this->getObjectFromCacheByParams( + $anr, + $objectData[$nameFiledKey], + $objectData['asset']['uuid'], + $objectScope, + $objectCategory?->getId() + ); + if ($object !== null) { + $this->objectObjectTable->deleteLinksByParentObject($object); + } + } + + $isImportTypeObject = $this->importCacheHelper + ->getValueFromArrayCache('import_type') === InstanceImportService::IMPORT_TYPE_OBJECT; + $currentObjectUuid = $objectData['uuid']; + if ($object === null) { + /* If IMPORT_TYPE_OBJECT then the process of informationRisks/amvs is done inside. */ + $asset = $this->assetImportProcessor->processAssetData($anr, $objectData['asset']); + + $rolfTag = null; + if (!empty($objectData['rolfTag'])) { + /* If IMPORT_TYPE_OBJECT then the process of $objectData['rolfTag']['rolfRisks'] is done inside. */ + $rolfTag = $this->rolfTagImportProcessor->processRolfTagData($anr, $objectData['rolfTag']); + } + + /* Avoid the UUID duplication. */ + if ($this->importCacheHelper->isItemInArrayCache('objects_uuids', $objectData['uuid'])) { + unset($objectData['uuid']); + } + /* In the new data structure there is only "label" field set. */ + if (isset($objectData['label'])) { + $objectData['label' . $anr->getLanguage()] = $objectData['label']; + } + $objectData[$nameFiledKey] = $this->prepareUniqueObjectName($objectData[$nameFiledKey]); + + $object = $this->anrObjectService + ->createMonarcObject($anr, $asset, $objectCategory, $rolfTag, $objectData, false); + + $this->importCacheHelper->addItemToArrayCache( + 'objects_by_name_asset_scope_category', + $object, + $objectData[$nameFiledKey] . $asset->getUuid() . $object->getScope() . $objectCategory?->getId() + ); + $this->importCacheHelper + ->addItemToArrayCache('objects_names', $objectData[$nameFiledKey], $objectData[$nameFiledKey]); + } elseif ($isImportTypeObject) { + /* If asset's amvs (information risks) are different, then update them. */ + if (!empty($objectData['asset']['informationRisks'])) { + $this->mergeAssetInformationRisks($object, $objectData['asset']['informationRisks']); + } + /* Validate if the RolfTag is the same or/and the linked to it operational risks are equal. */ + $this->mergeRolfTagOperationalRisks($anr, $object, $objectData['rolfTag']); + } + + $this->importCacheHelper->addItemToArrayCache('processed_objects_by_old_uuids', $object, $currentObjectUuid); + + /* Process objects links. */ + foreach ($objectData['children'] as $positionIndex => $childObjectData) { + $objectCategory = $this->objectCategoryImportProcessor + ->processObjectCategoryData($anr, $childObjectData['category'], $importMode); + $childObject = $this->processObjectData($anr, $objectCategory, $childObjectData, $importMode); + + $linksCacheKey = $object->getUuid() . $childObject->getUuid(); + if (!$object->hasChild($childObject) + && !$this->importCacheHelper->isItemInArrayCache('objects_links_uuids', $linksCacheKey) + ) { + $this->anrObjectObjectService->createObjectLink($object, $childObject, [ + 'position' => $positionIndex + 1, + 'forcePositionUpdate' => true, + ], false); + $this->importCacheHelper->addItemToArrayCache('objects_links_uuids', $linksCacheKey, $linksCacheKey); + } + } + + return $object; + } + + private function getObjectFromCacheByParams( + Entity\Anr $anr, + string $name, + string $assetUuid, + int $scope, + ?int $categoryId + ): ?Entity\MonarcObject { + if (!$this->importCacheHelper->isCacheKeySet('is_objects_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_objects_cache_loaded', true); + $languageIndex = $anr->getLanguage(); + /** @var Entity\MonarcObject $object */ + foreach ($this->monarcObjectTable->findByAnr($anr) as $object) { + $this->importCacheHelper->addItemToArrayCache('objects_uuids', $object->getUuid(), $object->getUuid()); + $this->importCacheHelper->addItemToArrayCache( + 'objects_by_name_asset_scope_category', + $object, + $object->getName($languageIndex) . $object->getAsset()->getUuid() . $object->getScope() + . $object->getCategory()?->getId() + ); + $this->importCacheHelper->addItemToArrayCache( + 'objects_names', + $object->getName($languageIndex), + $object->getName($languageIndex) + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache( + 'objects_by_name_asset_scope_category', + $name . $assetUuid . $scope . $categoryId + ); + } + + private function prepareUniqueObjectName(string $objectName, int $index = 1): string + { + if ($this->importCacheHelper->isItemInArrayCache('objects_names', $objectName)) { + if (str_contains($objectName, ' - Imp. #')) { + $objectName = preg_replace('/#\d+/', '#' . $index, $objectName); + } else { + $objectName .= ' - Imp. #' . $index; + } + + return $this->prepareUniqueObjectName($objectName, $index + 1); + } + + return $objectName; + } + + /** Merges the amvs (information risks) of the existing object. */ + private function mergeAssetInformationRisks(Entity\MonarcObject $object, array $informationRisksData): void + { + $existingAmvs = []; + /** @var Entity\Amv $amv */ + foreach ($object->getAsset()->getAmvs() as $amv) { + $existingAmvs[$amv->getUuid()] = $amv; + } + $importingAmvsData = []; + foreach ($informationRisksData as $informationRiskData) { + $importingAmvsData[$informationRiskData['uuid']] = $informationRiskData; + } + foreach (array_diff_key($importingAmvsData, $existingAmvs) as $newImportingAmvData) { + $amv = $this->informationRiskImportProcessor + ->processInformationRiskData($object->getAnr(), $newImportingAmvData); + /* Recreated instance risks if the object is instantiated. */ + foreach ($object->getInstances() as $instance) { + $this->anrInstanceRiskService->createInstanceRisk($instance, $amv, null, null, null, false); + } + } + /** @var Entity\Amv $existingAmvToRemove */ + 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); + $this->instanceRiskTable->save($instanceRiskToSetSpecific, false); + } + $this->amvTable->remove($existingAmvToRemove, false); + } + } + + /** Merges the rolfRisks (operational risks) of the existing object. */ + 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) { + /* 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) { + /* 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() !== null && $object->getRolfTag()->getCode() !== $rolfTagData['code']) { + /* 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 new file mode 100644 index 00000000..eac180c0 --- /dev/null +++ b/src/Import/Processor/OperationalInstanceRiskImportProcessor.php @@ -0,0 +1,399 @@ + 'BrutValue', 'netR' => 'NetValue', 'targetedR' => 'TargetedValue'], + ['brutO' => 'BrutValue', 'netO' => 'NetValue', 'targetedO' => 'TargetedValue'], + ['brutL' => 'BrutValue', 'netL' => 'NetValue', 'targetedL' => 'TargetedValue'], + ['brutF' => 'BrutValue', 'netF' => 'NetValue', 'targetedF' => 'TargetedValue'], + ['brutP' => 'BrutValue', 'netP' => 'NetValue', 'targetedP' => 'TargetedValue'], + ]; + + public function __construct( + private Table\OperationalInstanceRiskScaleTable $operationalInstanceRiskScaleTable, + private Table\OperationalRiskScaleTypeTable $operationalRiskScaleTypeTable, + private Table\InstanceRiskOpTable $instanceRiskOpTable, + private OperationalRiskImportProcessor $operationalRiskImportProcessor, + private OperationalRiskScaleImportProcessor $operationalRiskScaleImportProcessor, + private RecommendationImportProcessor $recommendationImportProcessor, + private ImportCacheHelper $importCacheHelper, + private InstanceRiskOwnerService $instanceRiskOwnerService, + private AnrInstanceRiskOpService $anrInstanceRiskOpService, + private AnrRecommendationRiskService $anrRecommendationRiskService, + ConnectedUserService $connectedUserService + ) { + $this->connectedUser = $connectedUserService->getConnectedUser(); + } + + public function processOperationalInstanceRisksData( + Entity\Anr $anr, + Entity\Instance $instance, + array $operationalInstanceRisksData + ): void { + $currentOperationalRiskScalesData = $this->operationalRiskScaleImportProcessor + ->getCurrentOperationalRiskScalesData($anr); + $externalOperationalRiskScalesData = []; + $areScalesLevelsOfLikelihoodDifferent = false; + $areImpactScaleTypesValuesDifferent = false; + $matchedScaleTypesMap = []; + $withEval = $this->importCacheHelper->getValueFromArrayCache('with_eval'); + $isImportTypeInstance = $this->importCacheHelper->getValueFromArrayCache( + 'import_type' + ) === InstanceImportService::IMPORT_TYPE_INSTANCE; + /* For the instances import with evaluations the values have to be converted to the current analysis scales. */ + if ($withEval && $isImportTypeInstance) { + $externalOperationalRiskScalesData = $this->operationalRiskScaleImportProcessor + ->getExternalOperationalRiskScalesData($anr, []); + if ($externalOperationalRiskScalesData === null) { + throw new Exception('The scales have to be prepared before the process of the operational risks.', 412); + } + $areScalesLevelsOfLikelihoodDifferent = $this->areLikelihoodScalesLevelsOfTypeDifferent( + $currentOperationalRiskScalesData, + $externalOperationalRiskScalesData + ); + $areImpactScaleTypesValuesDifferent = $this->areImpactScaleTypeValuesDifferent( + $currentOperationalRiskScalesData, + $externalOperationalRiskScalesData + ); + $matchedScaleTypesMap = $this->matchAndGetOperationalRiskScaleTypesMap( + $currentOperationalRiskScalesData, + $externalOperationalRiskScalesData + ); + } + foreach ($operationalInstanceRisksData as $operationalInstanceRiskData) { + $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, $operationalInstanceRiskData); + if ($this->importCacheHelper->getValueFromArrayCache('with_eval')) { + $operationalInstanceRisk + ->setBrutProb((int)$operationalInstanceRiskData['brutProb']) + ->setNetProb((int)$operationalInstanceRiskData['netProb']) + ->setTargetedProb((int)$operationalInstanceRiskData['targetedProb']) + ->setCacheBrutRisk((int)$operationalInstanceRiskData['cacheBrutRisk']) + ->setCacheNetRisk((int)$operationalInstanceRiskData['cacheNetRisk']) + ->setCacheTargetedRisk((int)$operationalInstanceRiskData['cacheTargetedRisk']) + ->setKindOfMeasure((int)$operationalInstanceRiskData['kindOfMeasure']) + ->setComment($operationalInstanceRiskData['comment'] ?? '') + ->setMitigation($operationalInstanceRiskData['mitigation'] ?? '') + ->setContext($operationalInstanceRiskData['context'] ?? ''); + if (!empty($instanceRiskData['riskOwner'])) { + $this->instanceRiskOwnerService + ->processRiskOwnerNameAndAssign($instanceRiskData['riskOwner'], $operationalInstanceRisk); + } + } + if ($areScalesLevelsOfLikelihoodDifferent) { + $this->operationalRiskScaleImportProcessor->adjustOperationalRisksProbabilityScales( + $operationalInstanceRisk, + $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD], + $currentOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD] + ); + } + + [$currentOperationalRiskScalesData, $areImpactScaleTypesValuesDifferent] = $this + ->processOperationalRiskScalesTypes( + $anr, + $instance, + $operationalInstanceRisk, + $currentOperationalRiskScalesData, + $externalOperationalRiskScalesData, + $matchedScaleTypesMap, + $operationalInstanceRiskData, + $areImpactScaleTypesValuesDifferent + ); + + if ($withEval) { + /* Recalculate the cached risk values. */ + $this->anrInstanceRiskOpService->updateRiskCacheValues($operationalInstanceRisk); + } + + /* Process the linked recommendations. */ + foreach ($operationalInstanceRiskData['recommendations'] ?? [] as $recommendationData) { + $recommendationSet = $this->recommendationImportProcessor + ->processRecommendationSetData($anr, $recommendationData['recommendationSet']); + $recommendation = $this->recommendationImportProcessor + ->processRecommendationData($recommendationSet, $recommendationData); + $this->anrRecommendationRiskService->createRecommendationRisk( + $recommendation, + $operationalInstanceRisk, + $recommendationData['commentAfter'] ?? '', + false + ); + } + + $this->instanceRiskOpTable->save($operationalInstanceRisk, false); + } + } + + private function processOperationalRiskScalesTypes( + Entity\Anr $anr, + Entity\Instance $instance, + Entity\InstanceRiskOp $operationalInstanceRisk, + array $currentOperationalRiskScalesData, + array $externalOperationalRiskScalesData, + array $matchedScaleTypesMap, + array $operationalInstanceRiskData, + bool $areImpactScaleTypesValuesDifferent + ): array { + $withEval = $this->importCacheHelper->getValueFromArrayCache('with_eval'); + $isImportTypeAnr = $this->importCacheHelper + ->getValueFromArrayCache('import_type') === InstanceImportService::IMPORT_TYPE_ANR; + + $currentImpactScaleData = $currentOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT]; + foreach ($currentImpactScaleData['operationalRiskScaleTypes'] as $index => $scaleType) { + /** @var Entity\OperationalRiskScaleType $operationalRiskScaleType */ + $operationalRiskScaleType = $scaleType['object']; + $operationalInstanceRiskScale = (new Entity\OperationalInstanceRiskScale()) + ->setAnr($anr) + ->setOperationalRiskScaleType($operationalRiskScaleType) + ->setOperationalInstanceRisk($operationalInstanceRisk) + ->setCreator($this->connectedUser->getEmail()); + + if ($withEval) { + /* The format is since v2.11.0 */ + if (isset($operationalInstanceRiskData['operationalInstanceRiskScales'])) { + $externalScaleTypeId = null; + if ($isImportTypeAnr) { + /* For anr import, match current scale type label with external ids. */ + $externalScaleTypeId = $this->importCacheHelper->getItemFromArrayCache( + 'operational_risk_scale_type_label_to_old_id', + $operationalRiskScaleType->getLabel() + ); + } elseif (isset($matchedScaleTypesMap['currentScaleTypeLabelToExternalIds'][ + $operationalRiskScaleType->getLabel() + ])) { + /* For instance import, match current scale type label with external ids. */ + $externalScaleTypeId = $matchedScaleTypesMap['currentScaleTypeLabelToExternalIds'][ + $operationalRiskScaleType->getLabel() + ]; + } + if ($externalScaleTypeId !== null + && isset($operationalInstanceRiskData['operationalInstanceRiskScales'][$externalScaleTypeId]) + ) { + $scalesValueData = $operationalInstanceRiskData['operationalInstanceRiskScales'][ + $externalScaleTypeId + ]; + $operationalInstanceRiskScale->setBrutValue($scalesValueData['brutValue']); + $operationalInstanceRiskScale->setNetValue($scalesValueData['netValue']); + $operationalInstanceRiskScale->setTargetedValue($scalesValueData['targetedValue']); + if ($areImpactScaleTypesValuesDifferent) { + /* We convert from the importing new scales to the current anr scales. */ + $this->operationalRiskScaleImportProcessor->adjustOperationalInstanceRisksScales( + $operationalInstanceRiskScale, + $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT], + $currentImpactScaleData + ); + } + } + /* The format before v2.11.0. Update only first 5 scales (ROLFP if not changed by user). */ + } elseif ($index < 5) { + foreach (static::$oldInstanceRiskFieldsMapToScaleTypesFields[$index] as $oldFiled => $typeField) { + $operationalInstanceRiskScale->{'set' . $typeField}($operationalInstanceRiskData[$oldFiled]); + } + if ($areImpactScaleTypesValuesDifferent) { + /* We convert from the importing new scales to the current anr scales. */ + $this->operationalRiskScaleImportProcessor->adjustOperationalInstanceRisksScales( + $operationalInstanceRiskScale, + $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT], + $currentImpactScaleData + ); + } + } + } + + $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); + } + + /* Process not matched operational risk scales types. */ + if (!empty($matchedScaleTypesMap['notMatchedScaleTypes']) && !$isImportTypeAnr) { + /* In case of instance import, there is a need to create external scale types in case if + the linked values are set for at least one operational instance risk. + The new created type has to be linked with all the existed risks. */ + foreach ($matchedScaleTypesMap['notMatchedScaleTypes'] as $extScaleTypeId => $extScaleTypeData) { + if (isset($operationalRiskData['operationalInstanceRiskScales'][$extScaleTypeId])) { + $scalesValueData = $operationalRiskData['operationalInstanceRiskScales'][$extScaleTypeId]; + if ($scalesValueData['netValue'] !== -1 + || $scalesValueData['brutValue'] !== -1 + || $scalesValueData['targetedValue'] !== -1 + ) { + $operationalRiskScaleType = (new Entity\OperationalRiskScaleType()) + ->setAnr($anr) + ->setOperationalRiskScale($currentImpactScaleData['object']) + ->setLabel($extScaleTypeData['label'] ?? $extScaleTypeData['translation']['value']) + ->setCreator($this->connectedUser->getEmail()); + $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType, false); + + foreach ($extScaleTypeData['operationalRiskScaleComments'] as $scaleCommentData) { + $this->operationalRiskScaleImportProcessor->createOrUpdateOperationalRiskScaleComment( + $anr, + false, + $currentImpactScaleData['object'], + $scaleCommentData, + [], + $operationalRiskScaleType + ); + } + + $operationalInstanceRiskScale = (new Entity\OperationalInstanceRiskScale()) + ->setAnr($anr) + ->setOperationalInstanceRisk($operationalInstanceRisk) + ->setOperationalRiskScaleType($operationalRiskScaleType) + ->setBrutValue($scalesValueData['brutValue']) + ->setNetValue($scalesValueData['netValue']) + ->setTargetedValue($scalesValueData['targetedValue']) + ->setCreator($this->connectedUser->getEmail()); + $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); + + $this->operationalRiskScaleImportProcessor->adjustOperationalInstanceRisksScales( + $operationalInstanceRiskScale, + $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT], + $currentImpactScaleData + ); + + /* To swap the scale risk between the two keys in the map as it is already matched. */ + unset($matchedScaleTypesMap['notMatchedScaleTypes'][$extScaleTypeId]); + $matchedScaleTypesMap['currentScaleTypeLabelToExternalIds'][$operationalRiskScaleType + ->getLabel()] = $extScaleTypeId; + + /* Due to the new scale type and related comments the cached the data has to be updated. */ + [$scaleTypesData, $commentsIndexToValueMap] = $this->operationalRiskScaleImportProcessor + ->prepareScaleTypesDataAndCommentsIndexToValueMap($currentImpactScaleData['object']); + $this->importCacheHelper->addItemToArrayCache('current_operational_risk_scales_data', [ + 'min' => $currentImpactScaleData['min'], + 'max' => $currentImpactScaleData['max'], + 'object' => $currentImpactScaleData['object'], + 'commentsIndexToValueMap' => $commentsIndexToValueMap, + 'operationalRiskScaleTypes' => $scaleTypesData, + ], OperationalRiskScaleSuperClass::TYPE_IMPACT); + $currentOperationalRiskScalesData = $this->operationalRiskScaleImportProcessor + ->getCurrentOperationalRiskScalesData($anr); + $areImpactScaleTypesValuesDifferent = true; + + /* Link the newly created scale type to all the existed operational risks. */ + $operationalInstanceRisks = $this->instanceRiskOpTable->findByAnrAndInstance( + $anr, + $instance + ); + foreach ($operationalInstanceRisks as $operationalInstanceRiskToUpdate) { + if ($operationalInstanceRiskToUpdate->getId() !== $operationalInstanceRisk->getId()) { + $this->operationalInstanceRiskScaleTable->save( + (new Entity\OperationalInstanceRiskScale()) + ->setAnr($anr) + ->setOperationalInstanceRisk($operationalInstanceRiskToUpdate) + ->setOperationalRiskScaleType($operationalRiskScaleType) + ->setCreator($this->connectedUser->getEmail()), + false + ); + } + } + } + } + } + } + + return [$currentOperationalRiskScalesData, $areImpactScaleTypesValuesDifferent]; + } + + private function matchAndGetOperationalRiskScaleTypesMap( + array $operationalRiskScalesData, + array $externalOperationalRiskScalesData + ): array { + $matchedScaleTypesMap = [ + 'currentScaleTypeLabelToExternalIds' => [], + 'notMatchedScaleTypes' => [], + ]; + $scaleTypesData = $operationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT][ + 'operationalRiskScaleTypes' + ]; + $externalScaleTypesData = $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT][ + 'operationalRiskScaleTypes' + ]; + foreach ($externalScaleTypesData as $externalScaleTypeData) { + $isMatched = false; + foreach ($scaleTypesData as $scaleTypeData) { + /** @var Entity\OperationalRiskScaleType $scaleType */ + $scaleType = $scaleTypeData['object']; + $externalLabel = $externalScaleTypeData['label'] ?? $externalScaleTypeData['translation']['value']; + if ($externalLabel === $scaleType->getLabel()) { + $matchedScaleTypesMap['currentScaleTypeLabelToExternalIds'][$scaleType->getLabel()] + = $externalScaleTypeData['id']; + $isMatched = true; + break; + } + } + if (!$isMatched) { + $matchedScaleTypesMap['notMatchedScaleTypes'][$externalScaleTypeData['id']] = $externalScaleTypeData; + } + } + + return $matchedScaleTypesMap; + } + + private function areLikelihoodScalesLevelsOfTypeDifferent( + array $operationalRiskScales, + array $externalOperationalRiskScalesData + ): bool { + $likelihoodType = OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD; + foreach ($operationalRiskScales as $scaleType => $operationalRiskScale) { + if ($scaleType === $likelihoodType) { + $externalScaleDataOfType = $externalOperationalRiskScalesData[$likelihoodType]; + if ($operationalRiskScale['min'] !== $externalScaleDataOfType['min'] + || $operationalRiskScale['max'] !== $externalScaleDataOfType['max']) { + return true; + } + } + } + + return false; + } + + /** + * Checks if any of the scale comments values related to the scale types have different scaleValue + * then in the new operational scale data. + */ + private function areImpactScaleTypeValuesDifferent( + array $operationalRiskScales, + array $extOperationalRiskScalesData + ): bool { + $impactType = OperationalRiskScaleSuperClass::TYPE_IMPACT; + foreach ($operationalRiskScales[$impactType]['commentsIndexToValueMap'] as $scaleIndex => $scaleValue) { + if (!isset($extOperationalRiskScalesData[$impactType]['commentsIndexToValueMap'][$scaleIndex])) { + return true; + } + $extScaleValue = $extOperationalRiskScalesData[$impactType]['commentsIndexToValueMap'][$scaleIndex]; + if ($scaleValue !== $extScaleValue) { + return true; + } + } + + return false; + } +} diff --git a/src/Import/Processor/OperationalRiskImportProcessor.php b/src/Import/Processor/OperationalRiskImportProcessor.php new file mode 100644 index 00000000..bca36e95 --- /dev/null +++ b/src/Import/Processor/OperationalRiskImportProcessor.php @@ -0,0 +1,95 @@ +processOperationalRiskData($anr, $operationalRiskData); + } + } + + public function processOperationalRiskData(Entity\Anr $anr, array $operationalRiskData): Entity\RolfRisk + { + $operationalRisk = $this->getRolfRiskFromCache($anr, $operationalRiskData['code']); + if ($operationalRisk === null) { + $operationalRisk = $this->anrRolfRiskService->create($anr, [ + 'code' => $operationalRiskData['code'], + 'label' . $anr->getLanguage() => + $operationalRiskData['label'] ?? $operationalRiskData['label' . $anr->getLanguage()], + 'description' . $anr->getLanguage() => + $operationalRiskData['label'] ?? $operationalRiskData['description' . $anr->getLanguage()], + ], false); + $this->importCacheHelper->addItemToArrayCache( + 'rolf_risks_by_code', + $operationalRisk, + $operationalRisk->getCode() + ); + } + + $saveOperationalRisk = false; + foreach ($operationalRiskData['measures'] as $measureData) { + $measure = $this->referentialImportProcessor->getMeasureFromCache($anr, $measureData['uuid']); + if ($measure === null && !empty($measureData['referential'])) { + $referential = $this->referentialImportProcessor->processReferentialData( + $anr, + $measureData['referential'] + ); + $measure = $this->referentialImportProcessor->processMeasureData($anr, $referential, $measureData); + } + if ($measure !== null) { + $operationalRisk->addMeasure($measure); + $saveOperationalRisk = true; + } + } + foreach ($operationalRiskData['rolfTags'] ?? [] as $rolfTagData) { + $rolfTag = $this->rolfTagImportProcessor->processRolfTagData($anr, $rolfTagData); + if (!$operationalRisk->hasRolfTag($rolfTag)) { + $saveOperationalRisk = true; + } + $operationalRisk->addTag($rolfTag); + } + + if ($saveOperationalRisk) { + $this->rolfRiskTable->save($operationalRisk, false); + $this->importCacheHelper + ->addItemToArrayCache('rolf_risks_by_code', $operationalRisk, $operationalRisk->getCode()); + } + + return $operationalRisk; + } + + private function getRolfRiskFromCache(Entity\Anr $anr, string $code): ?Entity\RolfRisk + { + if (!$this->importCacheHelper->isCacheKeySet('is_rolf_risks_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_rolf_risks_loaded', true); + /** @var Entity\RolfRisk $rolfRisk */ + foreach ($this->rolfRiskTable->findByAnr($anr) as $rolfRisk) { + $this->importCacheHelper->addItemToArrayCache('rolf_risks_by_code', $rolfRisk, $rolfRisk->getCode()); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('rolf_risks_by_code', $code); + } +} diff --git a/src/Import/Processor/OperationalRiskScaleImportProcessor.php b/src/Import/Processor/OperationalRiskScaleImportProcessor.php new file mode 100644 index 00000000..81d5a9e6 --- /dev/null +++ b/src/Import/Processor/OperationalRiskScaleImportProcessor.php @@ -0,0 +1,552 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function adjustOperationalRisksScaleValuesBasedOnNewScales(Entity\Anr $anr, array $data): void + { + /** @var Entity\InstanceRiskOp[] $operationalInstanceRisks */ + $operationalInstanceRisks = $this->instanceRiskOpTable->findByAnr($anr); + if (!empty($operationalInstanceRisks)) { + $currentOperationalRiskScalesData = $this->getCurrentOperationalRiskScalesData($anr); + $externalOperationalRiskScalesData = $this->getExternalOperationalRiskScalesData($anr, $data); + + foreach ($operationalInstanceRisks as $operationalInstanceRisk) { + $this->adjustOperationalRisksProbabilityScales( + $operationalInstanceRisk, + $currentOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD], + $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD] + ); + + foreach ($operationalInstanceRisk->getOperationalInstanceRiskScales() as $instanceRiskScale) { + $this->adjustOperationalInstanceRisksScales( + $instanceRiskScale, + $currentOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT], + $externalOperationalRiskScalesData[OperationalRiskScaleSuperClass::TYPE_IMPACT] + ); + } + + $this->instanceRiskOpTable->save($operationalInstanceRisk, false); + + $this->anrInstanceRiskOpService->updateRiskCacheValues($operationalInstanceRisk); + } + } + } + + public function adjustOperationalRisksProbabilityScales( + Entity\InstanceRiskOp $operationalInstanceRisk, + array $fromOperationalRiskScalesData, + array $toOperationalRiskScalesData + ): void { + foreach (['NetProb', 'BrutProb', 'TargetedProb'] as $likelihoodScaleName) { + $operationalInstanceRisk->{'set' . $likelihoodScaleName}( + $this->convertValueWithinNewScalesRange( + $operationalInstanceRisk->{'get' . $likelihoodScaleName}(), + $fromOperationalRiskScalesData['min'], + $fromOperationalRiskScalesData['max'], + $toOperationalRiskScalesData['min'], + $toOperationalRiskScalesData['max'] + ) + ); + } + } + + public function adjustOperationalInstanceRisksScales( + Entity\OperationalInstanceRiskScale $instanceRiskScale, + array $fromOperationalRiskScalesData, + array $toOperationalRiskScalesData + ): void { + foreach (['NetValue', 'BrutValue', 'TargetedValue'] as $impactScaleName) { + $scaleImpactValue = $instanceRiskScale->{'get' . $impactScaleName}(); + if ($scaleImpactValue === -1) { + continue; + } + $scaleImpactIndex = array_search( + $scaleImpactValue, + $fromOperationalRiskScalesData['commentsIndexToValueMap'], + true + ); + if ($scaleImpactIndex === false) { + continue; + } + + $approximatedIndex = $this->convertValueWithinNewScalesRange( + $scaleImpactIndex, + $fromOperationalRiskScalesData['min'], + $fromOperationalRiskScalesData['max'], + $toOperationalRiskScalesData['min'], + $toOperationalRiskScalesData['max'] + ); + + $approximatedValueToNewScales = $toOperationalRiskScalesData['commentsIndexToValueMap'][$approximatedIndex] + ?? $scaleImpactValue; + $instanceRiskScale->{'set' . $impactScaleName}($approximatedValueToNewScales); + + $this->operationalInstanceRiskScaleTable->save($instanceRiskScale, false); + } + } + + public function getCurrentOperationalRiskScalesData(Entity\Anr $anr): array + { + if (empty($this->importCacheHelper->isCacheKeySet('current_operational_risk_scales_data'))) { + /** @var Entity\OperationalRiskScale $operationalRiskScale */ + foreach ($this->operationalRiskScaleTable->findByAnr($anr) as $operationalRiskScale) { + [$scaleTypesData, $commentsIndexToValueMap] = $this->prepareScaleTypesDataAndCommentsIndexToValueMap( + $operationalRiskScale + ); + + $this->importCacheHelper->addItemToArrayCache('current_operational_risk_scales_data', [ + 'min' => $operationalRiskScale->getMin(), + 'max' => $operationalRiskScale->getMax(), + 'object' => $operationalRiskScale, + 'commentsIndexToValueMap' => $commentsIndexToValueMap, + 'operationalRiskScaleTypes' => $scaleTypesData, + ], $operationalRiskScale->getType()); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('current_operational_risk_scales_data'); + } + + /** + * Prepares and caches the new/importing operational risks scales. + * The format can be different, depends on the version (before v2.11.0 and after). + */ + public function getExternalOperationalRiskScalesData(Entity\Anr $anr, array $data): array + { + if (!empty($data)) { + $this->prepareExternalOperationalRiskScalesDataCache($anr, $data); + } + + return $this->importCacheHelper->getItemFromArrayCache('external_operational_risk_scales_data'); + } + + public function prepareExternalOperationalRiskScalesDataCache(Entity\Anr $anr, array $data): void + { + if (!$this->importCacheHelper->isCacheKeySet('external_operational_risk_scales_data')) { + /* Populate with informational risks scales if there is an import of a file exported prior v2.11.0. */ + $scalesDataResult = [ + OperationalRiskScaleSuperClass::TYPE_IMPACT => [ + 'min' => 0, + 'max' => $data['scales'][ScaleSuperClass::TYPE_IMPACT]['max'] + - $data['scales'][ScaleSuperClass::TYPE_IMPACT]['min'], + 'commentsIndexToValueMap' => [], + 'operationalRiskScaleTypes' => [], + 'operationalRiskScaleComments' => [], + ], + OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD => [ + 'min' => $data['scales'][ScaleSuperClass::TYPE_THREAT]['min'], + 'max' => $data['scales'][ScaleSuperClass::TYPE_THREAT]['max'], + 'commentsIndexToValueMap' => [], + 'operationalRiskScaleTypes' => [], + 'operationalRiskScaleComments' => [], + ], + ]; + if (!empty($data['operationalRiskScales'])) { + /* Overwrite the values for the version >= v2.11.0. */ + foreach ($data['operationalRiskScales'] as $operationalRiskScaleData) { + $scaleType = $operationalRiskScaleData['type']; + $scalesDataResult[$scaleType]['min'] = $operationalRiskScaleData['min']; + $scalesDataResult[$scaleType]['max'] = $operationalRiskScaleData['max']; + + /* Build the map of the comments index <=> values relation. */ + foreach ($operationalRiskScaleData['operationalRiskScaleTypes'] as $scaleTypeData) { + $scalesDataResult[$scaleType]['operationalRiskScaleTypes'][] = $scaleTypeData; + /* All the scale comment have the same index->value corresponding values, so populating once. */ + if (empty($scalesDataResult[$scaleType]['commentsIndexToValueMap'])) { + foreach ($scaleTypeData['operationalRiskScaleComments'] as $scaleTypeComment) { + if (!$scaleTypeComment['isHidden']) { + $scalesDataResult[$scaleType]['commentsIndexToValueMap'] + [$scaleTypeComment['scaleIndex']] = $scaleTypeComment['scaleValue']; + } + } + } + } + + $scalesDataResult[$scaleType]['operationalRiskScaleComments'] + = $operationalRiskScaleData['operationalRiskScaleComments']; + } + } else { + /* Convert comments and types from informational risks to operational (new format). */ + $scaleMin = $data['scales'][ScaleSuperClass::TYPE_IMPACT]['min']; + foreach (OperationalRiskScaleTypeSuperClass::getDefaultScalesImpacts() as $index => $scaleTypeLabels) { + /* Previous ROLFP scales impact types (types indexes were [4, 5, 6, 7, 8]). */ + $scalesDataResult[ScaleSuperClass::TYPE_IMPACT]['operationalRiskScaleTypes'][$index + 4] = [ + 'isHidden' => false, + 'label' => $scaleTypeLabels[$anr->getLanguageCode()], + ]; + } + foreach ($data['scalesComments'] as $scaleComment) { + $scaleType = $scaleComment['scale']['type']; + if (!\in_array($scaleType, [ScaleSuperClass::TYPE_IMPACT, ScaleSuperClass::TYPE_THREAT], true)) { + continue; + } + + $scaleCommentLabel = $scaleComment['comment'] ?? $scaleComment['comment' . $anr->getLanguage()]; + if ($scaleType === ScaleSuperClass::TYPE_THREAT) { + $scalesDataResult[$scaleType]['operationalRiskScaleComments'][] = [ + 'scaleIndex' => $scaleComment['val'], + 'scaleValue' => $scaleComment['val'], + 'isHidden' => false, + 'comment' => $scaleCommentLabel, + ]; + } elseif ($scaleType === ScaleSuperClass::TYPE_IMPACT && $scaleComment['val'] >= $scaleMin) { + $scaleIndex = $scaleComment['val'] - $scaleMin; + $scaleTypePosition = $scaleComment['scaleImpactType']['position']; + if (isset($scalesDataResult[$scaleType]['operationalRiskScaleTypes'][$scaleTypePosition])) { + $scalesDataResult[$scaleType]['operationalRiskScaleTypes'][$scaleTypePosition][ + 'operationalRiskScaleComments' + ][] = [ + 'scaleIndex' => $scaleIndex, + 'scaleValue' => $scaleComment['val'], + 'isHidden' => false, + 'comment' => $scaleCommentLabel, + ]; + + $scalesDataResult[$scaleType]['commentsIndexToValueMap'][$scaleIndex] + = $scaleComment['val']; + } + } + } + } + + $this->importCacheHelper->addItemToArrayCache( + 'external_operational_risk_scales_data', + $scalesDataResult[OperationalRiskScaleSuperClass::TYPE_IMPACT], + OperationalRiskScaleSuperClass::TYPE_IMPACT + ); + $this->importCacheHelper->addItemToArrayCache( + 'external_operational_risk_scales_data', + $scalesDataResult[OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD], + OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD + ); + } + } + + public function updateOperationalRisksScalesAndRelatedInstances(Entity\Anr $anr, array $data): void + { + $externalOperationalScalesData = $this->getExternalOperationalRiskScalesData($anr, $data); + /** @var Entity\OperationalRiskScale $operationalRiskScale */ + foreach ($this->operationalRiskScaleTable->findByAnr($anr) as $operationalRiskScale) { + $externalScaleData = $externalOperationalScalesData[$operationalRiskScale->getType()]; + $currentScaleLevelDifferenceFromExternal = $operationalRiskScale->getMax() - $externalScaleData['max']; + $operationalRiskScale + ->setAnr($anr) + ->setMin($externalScaleData['min']) + ->setMax($externalScaleData['max']) + ->setUpdater($this->connectedUser->getEmail()); + + /* This is currently only applicable for impact scales type. */ + $createdScaleTypes = []; + $matchedScaleTypes = []; + foreach ($externalScaleData['operationalRiskScaleTypes'] as $scaleTypeData) { + $isScaleTypeMatched = true; + $externalScaleTypeLabel = $scaleTypeData['label'] ?? $scaleTypeData['translation']['value']; + $operationalRiskScaleType = $this->matchScaleTypeWithScaleTypesListByLabel( + $operationalRiskScale->getOperationalRiskScaleTypes(), + $externalScaleTypeLabel + ); + if ($operationalRiskScaleType === null) { + $isScaleTypeMatched = false; + $operationalRiskScaleType = (new Entity\OperationalRiskScaleType()) + ->setAnr($anr) + ->setOperationalRiskScale($operationalRiskScale) + ->setLabel($externalScaleTypeLabel) + ->setCreator($this->connectedUser->getEmail()); + + $createdScaleTypes[$operationalRiskScaleType->getLabel()] = $operationalRiskScaleType; + } elseif ($currentScaleLevelDifferenceFromExternal !== 0) { + $matchedScaleTypes[$operationalRiskScaleType->getId()] = $operationalRiskScaleType; + } + + /* The map is used to match for the importing operational risks, scale values with scale types. */ + $this->importCacheHelper->addItemToArrayCache( + 'operational_risk_scale_type_label_to_old_id', + $scaleTypeData['id'], + $operationalRiskScaleType->getLabel() + ); + + $operationalRiskScaleType->setIsHidden($scaleTypeData['isHidden']); + $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType, false); + + foreach ($scaleTypeData['operationalRiskScaleComments'] as $scaleTypeCommentData) { + $this->createOrUpdateOperationalRiskScaleComment( + $anr, + $isScaleTypeMatched, + $operationalRiskScale, + $scaleTypeCommentData, + $operationalRiskScaleType->getOperationalRiskScaleComments(), + $operationalRiskScaleType + ); + } + } + + /* Create relations of all the created scales with existed risks. */ + if (!empty($createdScaleTypes)) { + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + foreach ($this->instanceRiskOpTable->findByAnr($anr) as $operationalInstanceRisk) { + foreach ($createdScaleTypes as $createdScaleType) { + $operationalInstanceRiskScale = (new Entity\OperationalInstanceRiskScale()) + ->setAnr($anr) + ->setOperationalRiskScaleType($createdScaleType) + ->setOperationalInstanceRisk($operationalInstanceRisk) + ->setCreator($this->connectedUser->getEmail()); + $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); + } + } + } + + $maxIndexForLikelihood = 0; + /* This is currently applicable only for likelihood scales type */ + foreach ($externalScaleData['operationalRiskScaleComments'] as $scaleCommentData) { + $this->createOrUpdateOperationalRiskScaleComment( + $anr, + true, + $operationalRiskScale, + $scaleCommentData, + $operationalRiskScale->getOperationalRiskScaleComments(), + ); + $maxIndexForLikelihood = (int)$scaleCommentData['scaleIndex'] > $maxIndexForLikelihood + ? (int)$scaleCommentData['scaleIndex'] + : $maxIndexForLikelihood; + } + /* Manage a case when the scale (probability) is not matched and level higher than external. */ + if ($maxIndexForLikelihood !== 0 + && $operationalRiskScale->getType() === OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD + ) { + foreach ($operationalRiskScale->getOperationalRiskScaleComments() as $comment) { + if ($comment->getScaleIndex() >= $maxIndexForLikelihood) { + $comment->setIsHidden(true); + $this->operationalRiskScaleCommentTable->save($comment, false); + } + } + } + + /* Validate if any existed comments are now out of the new scales bound and if their values are valid. + Also, if their comments are complete per scale's level. */ + if ($currentScaleLevelDifferenceFromExternal !== 0) { + /** @var Entity\OperationalRiskScaleType $operationalRiskScaleType */ + foreach ($operationalRiskScale->getOperationalRiskScaleTypes() as $operationalRiskScaleType) { + /* Ignore the currently created scale types. */ + if (\array_key_exists($operationalRiskScaleType->getLabel(), $createdScaleTypes)) { + continue; + } + + if ($currentScaleLevelDifferenceFromExternal < 0 + && !\array_key_exists($operationalRiskScaleType->getId(), $matchedScaleTypes) + ) { + /* The scales type was not matched and the current scales level is lower than external, + so we need to create missing empty scales comments. */ + $commentIndex = $operationalRiskScale->getMax() + $currentScaleLevelDifferenceFromExternal + 1; + $commentIndexToValueMap = $externalOperationalScalesData[ + OperationalRiskScaleSuperClass::TYPE_IMPACT + ]['commentsIndexToValueMap']; + while ($commentIndex <= $operationalRiskScale->getMax()) { + $this->createOrUpdateOperationalRiskScaleComment($anr, false, $operationalRiskScale, [ + 'scaleIndex' => $commentIndex, + 'scaleValue' => $commentIndexToValueMap[$commentIndex], + 'isHidden' => false, + 'comment' => '', + ], [], $operationalRiskScaleType); + $commentIndex++; + } + + continue; + } + + if ($currentScaleLevelDifferenceFromExternal > 0) { + $commentIndexToValueMap = $externalOperationalScalesData[ + OperationalRiskScaleSuperClass::TYPE_IMPACT + ]['commentsIndexToValueMap']; + $maxValue = $commentIndexToValueMap[$operationalRiskScale->getMax()]; + if (\array_key_exists($operationalRiskScaleType->getId(), $matchedScaleTypes)) { + /* The scales type was matched and the current scales level is higher than external, + so we need to hide their comments and validate values. */ + foreach ($matchedScaleTypes as $matchedScaleType) { + $this->processCurrentScalesCommentsWhenLimitIsHigher( + $operationalRiskScale, + $matchedScaleType, + $maxValue + ); + } + } else { + /* Manage a case when the scale is not matched and level higher than external */ + $this->processCurrentScalesCommentsWhenLimitIsHigher( + $operationalRiskScale, + $operationalRiskScaleType, + $maxValue + ); + } + } + } + } + + $this->operationalRiskScaleTable->save($operationalRiskScale, false); + + [$scaleTypesData, $commentsIndexToValueMap] = $this->prepareScaleTypesDataAndCommentsIndexToValueMap( + $operationalRiskScale + ); + /* Update the values in the cache. */ + $this->importCacheHelper->addItemToArrayCache('current_operational_risk_scales_data', [ + 'min' => $operationalRiskScale->getMin(), + 'max' => $operationalRiskScale->getMax(), + 'object' => $operationalRiskScale, + 'commentsIndexToValueMap' => $commentsIndexToValueMap, + 'operationalRiskScaleTypes' => $scaleTypesData, + ], $operationalRiskScale->getType()); + } + } + + public function createOrUpdateOperationalRiskScaleComment( + Entity\Anr $anr, + bool $isMatchRequired, + Entity\OperationalRiskScale $operationalRiskScale, + array $scaleCommentData, + iterable $scaleCommentsToMatchWith, + ?Entity\OperationalRiskScaleType $operationalRiskScaleType = null + ): Entity\OperationalRiskScaleComment { + $operationalRiskScaleComment = null; + if ($isMatchRequired) { + $operationalRiskScaleComment = $this->matchScaleCommentDataWithScaleCommentsList( + $operationalRiskScale, + $scaleCommentData, + $scaleCommentsToMatchWith, + ); + } + if ($operationalRiskScaleComment === null) { + $operationalRiskScaleComment = (new Entity\OperationalRiskScaleComment()) + ->setAnr($anr) + ->setOperationalRiskScale($operationalRiskScale) + ->setComment($scaleCommentData['comment'] ?? $scaleCommentData['translation']['value']) + ->setCreator($this->connectedUser->getEmail()); + } + + if ($operationalRiskScaleType !== null) { + $operationalRiskScaleComment->setOperationalRiskScaleType($operationalRiskScaleType); + } + + $operationalRiskScaleComment + ->setScaleIndex($scaleCommentData['scaleIndex']) + ->setScaleValue($scaleCommentData['scaleValue']) + ->setIsHidden($scaleCommentData['isHidden']); + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + + return $operationalRiskScaleComment; + } + + public function prepareScaleTypesDataAndCommentsIndexToValueMap( + Entity\OperationalRiskScale $operationalRiskScale + ): array { + $scaleTypesData = []; + $commentsIndexToValueMap = []; + /* Build the map of the comments index <=> values relation. */ + foreach ($operationalRiskScale->getOperationalRiskScaleTypes() as $scaleType) { + /* The operational risk scale types object is used to recreate operational instance risk scales. */ + $scaleTypesData[]['object'] = $scaleType; + /* All the scale comment have the same index -> value corresponding values, so populating once. */ + if (empty($commentsIndexToValueMap)) { + foreach ($scaleType->getOperationalRiskScaleComments() as $scaleTypeComment) { + if (!$scaleTypeComment->isHidden()) { + $commentsIndexToValueMap[$scaleTypeComment->getScaleIndex()] = + $scaleTypeComment->getScaleValue(); + } + } + } + } + + return [$scaleTypesData, $commentsIndexToValueMap]; + } + + /** + * @param Entity\OperationalRiskScaleComment[] $operationalRiskScaleComments + */ + private function matchScaleCommentDataWithScaleCommentsList( + Entity\OperationalRiskScale $operationalRiskScale, + array $scaleTypeCommentData, + iterable $operationalRiskScaleComments, + ): ?Entity\OperationalRiskScaleComment { + foreach ($operationalRiskScaleComments as $operationalRiskScaleComment) { + if ($operationalRiskScaleComment->getScaleIndex() === $scaleTypeCommentData['scaleIndex'] + && $operationalRiskScale->getId() === $operationalRiskScaleComment->getOperationalRiskScale()->getId() + ) { + $commentLabel = $scaleTypeCommentData['comment'] ?? $scaleTypeCommentData['translation']['value']; + if ($operationalRiskScaleComment->getComment() !== $commentLabel) { + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + } + + return $operationalRiskScaleComment; + } + } + + return null; + } + + /** + * Matches local operational risks' scale types with importing ones by label or translation value (prior v2.13.1). + * + * @param Entity\OperationalRiskScaleType[] $operationalRiskScaleTypes + */ + private function matchScaleTypeWithScaleTypesListByLabel( + iterable $operationalRiskScaleTypes, + string $scaleTypeLabel, + ): ?Entity\OperationalRiskScaleType { + foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { + if ($operationalRiskScaleType->getLabel() === $scaleTypeLabel) { + return $operationalRiskScaleType; + } + } + + return null; + } + + private function processCurrentScalesCommentsWhenLimitIsHigher( + Entity\OperationalRiskScale $operationalRiskScale, + Entity\OperationalRiskScaleType $operationalRiskScaleType, + int $maxValue + ): void { + foreach ($operationalRiskScaleType->getOperationalRiskScaleComments() as $comment) { + $isHidden = $operationalRiskScale->getMin() > $comment->getScaleIndex() + || $operationalRiskScale->getMax() < $comment->getScaleIndex(); + $comment->setIsHidden($isHidden); + if ($isHidden && $maxValue >= $comment->getScaleValue()) { + $comment->setScaleValue(++$maxValue); + } + + $this->operationalRiskScaleCommentTable->save($comment, false); + } + } +} diff --git a/src/Import/Processor/RecommendationImportProcessor.php b/src/Import/Processor/RecommendationImportProcessor.php new file mode 100644 index 00000000..8284793f --- /dev/null +++ b/src/Import/Processor/RecommendationImportProcessor.php @@ -0,0 +1,158 @@ +processRecommendationSetData($anr, $recommendationSetData); + } + } + + public function processRecommendationSetData( + Entity\Anr $anr, + array $recommendationSetData + ): Entity\RecommendationSet { + $labelKey = 'label' . $anr->getLanguage(); + /* Supports the structure format prior v2.13.1 */ + if (isset($recommendationSetData[$labelKey]) && !isset($recommendationSetData['label'])) { + $recommendationSetData['label'] = $recommendationSetData[$labelKey]; + } + $recommendationSet = $this + ->getRecommendationSetFromCache($anr, $recommendationSetData['uuid'], $recommendationSetData['label']); + if ($recommendationSet === null) { + $recommendationSet = $this->anrRecommendationSetService->create($anr, $recommendationSetData, false); + $this->importCacheHelper->addItemToArrayCache( + 'recommendations_sets', + $recommendationSet, + $recommendationSet->getUuid() + ); + } + + if (!empty($recommendationSetData['recommendations'])) { + $this->processRecommendationsData($recommendationSet, $recommendationSetData['recommendations']); + } + + return $recommendationSet; + } + + public function processRecommendationsData( + Entity\RecommendationSet $recommendationSet, + array $recommendationsData + ): void { + foreach ($recommendationsData as $recommendationData) { + $this->processRecommendationData($recommendationSet, $recommendationData); + } + } + + public function processRecommendationData( + Entity\RecommendationSet $recommendationSet, + array $recommendationData + ): Entity\Recommendation { + $anr = $recommendationSet->getAnr(); + $recommendation = $this->getRecommendationFromCache($anr, $recommendationData['uuid']); + if ($recommendation !== null) { + return $recommendation; + } + + /* The code should be unique within recommendations sets. */ + if (\in_array($recommendationData['code'], $this->importCacheHelper->getItemFromArrayCache( + 'recommendations_codes_by_set_uuid', + $recommendationSet->getUuid() + ) ?? [], true)) { + $recommendationData['code'] .= '-' . time(); + } + + $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()); + + return $recommendation; + } + + private function getRecommendationFromCache(Entity\Anr $anr, string $uuid): ?Entity\Recommendation + { + $this->prepareRecommendationsCache($anr); + + return $this->importCacheHelper->getItemFromArrayCache('recommendations', $uuid); + } + + private function getRecommendationSetFromCache( + Entity\Anr $anr, + string $uuid, + string $label + ): ?Entity\RecommendationSet { + $this->prepareRecommendationsCache($anr); + + $recommendationSet = $this->importCacheHelper->getItemFromArrayCache('recommendations_sets', $uuid); + if ($recommendationSet === null && $label !== '') { + /** @var Entity\RecommendationSet $set */ + foreach ($this->importCacheHelper->getItemFromArrayCache('recommendations_sets') ?? [] as $set) { + if ($set->getLabel() === $label) { + $recommendationSet = $set; + break; + } + } + } + + return $recommendationSet; + } + + private function prepareRecommendationsCache(Entity\Anr $anr): void + { + if (!$this->importCacheHelper->isCacheKeySet('is_recommendations_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_recommendations_cache_loaded', true); + $this->maxRecommendationPosition = $this->recommendationTable->findMaxPosition(['anr' => $anr]); + /** @var Entity\RecommendationSet $recommendationSet */ + foreach ($this->recommendationSetTable->findByAnr($anr) as $recommendationSet) { + $this->importCacheHelper->addItemToArrayCache( + 'recommendations_sets', + $recommendationSet, + $recommendationSet->getUuid() + ); + $recommendationsCodes = []; + foreach ($recommendationSet->getRecommendations() as $recommendation) { + $this->importCacheHelper->addItemToArrayCache( + 'recommendations', + $recommendation, + $recommendation->getUuid() + ); + $recommendationsCodes[] = $recommendation->getCode(); + } + $this->importCacheHelper->addItemToArrayCache( + 'recommendations_codes_by_set_uuid', + $recommendationsCodes, + $recommendationSet->getUuid() + ); + } + } + } +} diff --git a/src/Import/Processor/ReferentialImportProcessor.php b/src/Import/Processor/ReferentialImportProcessor.php new file mode 100644 index 00000000..43cd89aa --- /dev/null +++ b/src/Import/Processor/ReferentialImportProcessor.php @@ -0,0 +1,199 @@ +processReferentialData($anr, $referentialData); + } + } + + public function processReferentialData(Entity\Anr $anr, array $referentialData): Entity\Referential + { + $referential = $this->getReferentialFromCache($anr, $referentialData['uuid']); + if ($referential === null) { + /* In the new data structure there is only "label" field set. */ + if (isset($referentialData['label'])) { + $referentialData['label' . $anr->getLanguage()] = $referentialData['label']; + } + + $referential = $this->anrReferentialService->create($anr, $referentialData, false); + $this->importCacheHelper->addItemToArrayCache('referentials', $referential, $referential->getUuid()); + } + + if (!empty($referentialData['measures'])) { + $this->processMeasuresData($anr, $referential, $referentialData['measures']); + } + + return $referential; + } + + public function processMeasuresData(Entity\Anr $anr, Entity\Referential $referential, array $measuresData): void + { + foreach ($measuresData as $measureData) { + $this->processMeasureData($anr, $referential, $measureData); + } + } + + public function processMeasureData( + Entity\Anr $anr, + Entity\Referential $referential, + array $measureData + ): Entity\Measure { + $measure = $this->getMeasureFromCache($anr, $measureData['uuid']); + if ($measure === null) { + /* The code should be unique. */ + if (\in_array($measureData['code'], $this->importCacheHelper->getItemFromArrayCache( + 'measures_codes_by_ref_uuid', + $referential->getUuid() + ) ?? [], true)) { + $measureData['code'] .= '-' . time(); + } + + /* In the new data structure there is only "label" field set. */ + if (isset($measureData['label'])) { + $measureData['label' . $anr->getLanguage()] = $measureData['label']; + } + + $soaCategory = $this->processSoaCategoryData($anr, $referential, $measureData); + + $measure = $this->anrMeasureService + ->createMeasureObject($anr, $referential, $soaCategory, $measureData, false); + $this->importCacheHelper->addItemToArrayCache('measures', $measure, $measure->getUuid()); + + $soa = $this->soaService->createSoaObject($anr, $measure); + $this->importCacheHelper->addItemToArrayCache('soas_by_measure_uuids', $soa, $measure->getUuid()); + } + + $this->processLinkedMeasures($anr, $measure, $measureData); + + return $measure; + } + + public function processLinkedMeasures(Entity\Anr $anr, Entity\Measure $measure, array $measureData): void + { + if (!empty($measureData['linkedMeasures'])) { + foreach ($measureData['linkedMeasures'] as $linkedMeasureData) { + $linkedMeasure = $this->getMeasureFromCache($anr, $linkedMeasureData['uuid']); + if ($linkedMeasure !== null) { + $measure->addLinkedMeasure($linkedMeasure); + $this->measureTable->save($measure, false); + } + } + } + } + + public function processSoaCategoryData( + Entity\Anr $anr, + Entity\Referential $referential, + array $measureData + ): ?Entity\SoaCategory { + $soaCategory = null; + if (!empty($measureData['category'])) { + /* Support the previous structure format. */ + $soaCategoryLabel = $measureData['category']; + if (!empty($soaCategoryLabel['label'])) { + $soaCategoryLabel = $soaCategoryLabel['label']; + } elseif (!empty($soaCategoryLabel['label' . $anr->getLanguage()])) { + $soaCategoryLabel = $soaCategoryLabel['label' . $anr->getLanguage()]; + } + $soaCategory = $this->getSoaCategoryFromCache($anr, $referential->getUuid() . '_' . $soaCategoryLabel); + if ($soaCategory === null) { + $soaCategory = $this->soaCategoryService->create($anr, [ + 'referential' => $referential, + 'label' . $anr->getLanguage() => $soaCategoryLabel, + ], false); + $this->importCacheHelper->addItemToArrayCache( + 'soa_categories_by_referential_uuid_and_label', + $soaCategory, + $referential->getUuid() . '_' . $soaCategoryLabel + ); + } + } + + return $soaCategory; + } + + public function getReferentialFromCache(Entity\Anr $anr, string $referentialUuid): ?Entity\Referential + { + $this->prepareReferentialsAndMeasuresCache($anr); + + return $this->importCacheHelper->getItemFromArrayCache('referentials', $referentialUuid); + } + + public function getMeasureFromCache(Entity\Anr $anr, string $measureUuid): ?Entity\Measure + { + $this->prepareReferentialsAndMeasuresCache($anr); + + return $this->importCacheHelper->getItemFromArrayCache('measures', $measureUuid); + } + + private function getSoaCategoryFromCache(Entity\Anr $anr, string $refUuidAndSoaCatLabel): ?Entity\SoaCategory + { + if (!$this->importCacheHelper->isCacheKeySet('is_soa_categories_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_soa_categories_cache_loaded', true); + /** @var Entity\SoaCategory $soaCategory */ + foreach ($this->soaCategoryTable->findByAnr($anr) as $soaCategory) { + $this->importCacheHelper->addItemToArrayCache( + 'soa_categories_by_referential_uuid_and_label', + $soaCategory, + $soaCategory->getReferential()->getUuid() . '_' . $soaCategory->getLabel($anr->getLanguage()) + ); + } + } + + return $this->importCacheHelper + ->getItemFromArrayCache('soa_categories_by_referential_uuid_and_label', $refUuidAndSoaCatLabel); + } + + private function prepareReferentialsAndMeasuresCache(Entity\Anr $anr): void + { + if (!$this->importCacheHelper->isCacheKeySet('is_referentials_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_referentials_cache_loaded', true); + /** @var Entity\Referential $referential */ + foreach ($this->referentialTable->findByAnr($anr) as $referential) { + $this->importCacheHelper->addItemToArrayCache('referentials', $referential, $referential->getUuid()); + $measuresCodes = []; + foreach ($referential->getMeasures() as $measure) { + $this->importCacheHelper->addItemToArrayCache('measures', $measure, $measure->getUuid()); + $measuresCodes[] = $measure->getCode(); + } + $this->importCacheHelper->addItemToArrayCache( + 'measures_codes_by_ref_uuid', + $measuresCodes, + $referential->getUuid() + ); + } + } + } +} diff --git a/src/Import/Processor/RolfTagImportProcessor.php b/src/Import/Processor/RolfTagImportProcessor.php new file mode 100644 index 00000000..df38668a --- /dev/null +++ b/src/Import/Processor/RolfTagImportProcessor.php @@ -0,0 +1,68 @@ +processRolfTagData($anr, $rolfTagData); + } + } + + public function processRolfTagData(Entity\Anr $anr, array $rolfTagData): Entity\RolfTag + { + $rolfTag = $this->getRolfTagFromCache($anr, $rolfTagData['code']); + if ($rolfTag !== null) { + return $rolfTag; + } + + /* In the new data structure there is only "label" field set. */ + if (isset($rolfTagData['label'])) { + $rolfTagData['label' . $anr->getLanguage()] = $rolfTagData['label']; + } + + $rolfTag = $this->anrRolfTagService->create($anr, $rolfTagData, false); + $this->importCacheHelper->addItemToArrayCache('rolf_tags_by_code', $rolfTag, $rolfTag->getCode()); + + /* For the objects and instance risks data the "rolfRisks" are inside the "rolfTag". + For the knowledge base data the rolfTags don't contain "rolfRisks." */ + if (!empty($rolfTagData['rolfRisks'])) { + $this->operationalRiskImportProcessor->processOperationalRisksData($anr, $rolfTagData['rolfRisks']); + } + + return $rolfTag; + } + + public function getRolfTagFromCache(Entity\Anr $anr, string $code): ?Entity\RolfTag + { + if (!$this->importCacheHelper->isCacheKeySet('is_rolf_tags_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_rolf_tags_cache_loaded', true); + /** @var Entity\RolfTag $rolfTag */ + foreach ($this->rolfTagTable->findByAnr($anr) as $rolfTag) { + $this->importCacheHelper->addItemToArrayCache('rolf_tags_by_code', $rolfTag, $rolfTag->getCode()); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('rolf_tags_by_code', $code); + } +} diff --git a/src/Import/Processor/ScaleImportProcessor.php b/src/Import/Processor/ScaleImportProcessor.php new file mode 100644 index 00000000..c3cbb281 --- /dev/null +++ b/src/Import/Processor/ScaleImportProcessor.php @@ -0,0 +1,492 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function applyNewScalesFromData(Entity\Anr $anr, array $newScalesData): void + { + $scalesDiff = []; + /** @var Entity\Scale $scale */ + foreach ($this->scaleTable->findByAnr($anr) as $scale) { + /* Update the scales impact types and comments. It's only applied for the new structure since v2.13.1. */ + if (!empty($newScalesData[ScaleSuperClass::TYPE_IMPACT]['scaleImpactTypes'])) { + $this->applyNewScaleImpactTypesAndComments( + $anr, + $scale, + $newScalesData[ScaleSuperClass::TYPE_IMPACT]['scaleImpactTypes'] + ); + } + + if ($scale->isScaleRangeDifferentFromData($newScalesData)) { + if ($scale->getType() === ScaleSuperClass::TYPE_IMPACT) { + /* All the instance's risks and consequences values have to be updated. */ + $scalesDiff[ScaleSuperClass::TYPE_IMPACT] = [ + 'currentRange' => ['min' => $scale->getMin(), 'max', $scale->getMax()], + 'newRange' => [ + 'min' => $newScalesData[ScaleSuperClass::TYPE_IMPACT]['min'], + 'max' => $newScalesData[ScaleSuperClass::TYPE_IMPACT]['max'], + ], + ]; + } elseif ($scale->getType() === ScaleSuperClass::TYPE_THREAT) { + /* All the threats rates' values and qualification have to be updated. */ + $this->updateThreatsQualification($anr, $scale, $newScalesData[ScaleSuperClass::TYPE_THREAT]); + + $scalesDiff[ScaleSuperClass::TYPE_THREAT] = [ + 'currentRange' => ['min' => $scale->getMin(), 'max', $scale->getMax()], + 'newRange' => [ + 'min' => $newScalesData[ScaleSuperClass::TYPE_THREAT]['min'], + 'max' => $newScalesData[ScaleSuperClass::TYPE_THREAT]['max'], + ], + ]; + } elseif ($scale->getType() === ScaleSuperClass::TYPE_VULNERABILITY) { + /* All the vulnerabilities' risks values have to be updated. */ + $scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY] = [ + 'currentRange' => ['min' => $scale->getMin(), 'max', $scale->getMax()], + 'newRange' => [ + 'min' => $newScalesData[ScaleSuperClass::TYPE_VULNERABILITY]['min'], + 'max' => $newScalesData[ScaleSuperClass::TYPE_VULNERABILITY]['max'], + ], + ]; + } + + $scale->setMin($newScalesData[$scale->getType()]['min']) + ->setMax($newScalesData[$scale->getType()]['max']) + ->setUpdater($this->connectedUser->getEmail()); + $this->scaleTable->save($scale, false); + } + } + + /* If any type of the scale has difference in range than the risks and other values have to be updated. */ + $this->updateInstancesConsequencesThreatsVulnerabilitiesAndRisks($anr, $scalesDiff); + } + + /** Prepares the current analysis and external importing scales data cache. */ + public function prepareScalesCache(Entity\Anr $anr, array $externalScalesData): void + { + $this->prepareExternalScalesCache($externalScalesData); + if (!$this->importCacheHelper->isCacheKeySet('current_scales_data_by_type')) { + /** @var Entity\Scale $scale */ + foreach ($this->scaleTable->findByAnr($anr) as $scale) { + $this->importCacheHelper->addItemToArrayCache('current_scales_data_by_type', [ + 'min' => $scale->getMin(), + 'max' => $scale->getMax(), + 'object' => $scale, + ], $scale->getType()); + } + } + } + + public function getCurrentScaleFromCacheByType(int $type): ?Entity\Scale + { + return $this->importCacheHelper->isCacheKeySet('current_scales_data_by_type') + ? $this->importCacheHelper->getItemFromArrayCache('current_scales_data_by_type', $type)['object'] + : null; + } + + public function prepareExternalScalesCache(array $externalScalesData): void + { + if (!$this->importCacheHelper->isCacheKeySet('external_scales_data_by_type')) { + foreach ($externalScalesData as $externalScaleData) { + $this->importCacheHelper->addItemToArrayCache('external_scales_data_by_type', [ + 'min' => $externalScaleData['min'], + 'max' => $externalScaleData['max'], + ], $externalScaleData['type']); + } + } + } + + public function updateInstancesConsequencesThreatsVulnerabilitiesAndRisks(Entity\Anr $anr, array $scalesDiff): void + { + if (empty($scalesDiff)) { + return; + } + + if (isset($scalesDiff[ScaleSuperClass::TYPE_IMPACT])) { + /** @var Entity\InstanceConsequence $consequence */ + foreach ($this->instanceConsequenceTable->findByAnr($anr) as $consequence) { + $consequence->setConfidentiality( + $consequence->isHidden() ? -1 : $this->convertValueWithinNewScalesRange( + $consequence->getConfidentiality(), + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['max'] + ) + ); + $consequence->setIntegrity( + $consequence->isHidden() ? -1 : $this->convertValueWithinNewScalesRange( + $consequence->getIntegrity(), + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['max'] + ) + ); + $consequence->setAvailability( + $consequence->isHidden() ? -1 : $this->convertValueWithinNewScalesRange( + $consequence->getAvailability(), + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['max'] + ) + ); + + $this->instanceConsequenceTable->save($consequence, false); + } + } + + /** @var Entity\Instance $instance */ + foreach ($this->instanceTable->findByAnr($anr) as $instance) { + if (isset($scalesDiff[ScaleSuperClass::TYPE_IMPACT])) { + if ($instance->getConfidentiality() !== -1) { + $instance->setConfidentiality($this->convertValueWithinNewScalesRange( + $instance->getConfidentiality(), + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['max'] + )); + } + if ($instance->getIntegrity() !== -1) { + $instance->setIntegrity($this->convertValueWithinNewScalesRange( + $instance->getIntegrity(), + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['max'] + )); + } + if ($instance->getAvailability() !== -1) { + $instance->setAvailability($this->convertValueWithinNewScalesRange( + $instance->getAvailability(), + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_IMPACT]['newRange']['max'] + )); + } + + $this->instanceTable->save($instance, false); + } + + if (isset($scalesDiff[ScaleSuperClass::TYPE_THREAT]) + || isset($scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY]) + ) { + foreach ($instance->getInstanceRisks() as $instanceRisk) { + if (isset($scalesDiff[ScaleSuperClass::TYPE_THREAT])) { + $instanceRisk->setThreatRate($this->convertValueWithinNewScalesRange( + $instanceRisk->getThreatRate(), + $scalesDiff[ScaleSuperClass::TYPE_THREAT]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_THREAT]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_THREAT]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_THREAT]['newRange']['max'] + )); + } + if (isset($scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY])) { + $oldVulRate = $instanceRisk->getVulnerabilityRate(); + $instanceRisk->setVulnerabilityRate($this->convertValueWithinNewScalesRange( + $instanceRisk->getVulnerabilityRate(), + $scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY]['currentRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY]['currentRange']['max'], + $scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY]['newRange']['min'], + $scalesDiff[ScaleSuperClass::TYPE_VULNERABILITY]['newRange']['max'] + )); + $newVulRate = $instanceRisk->getVulnerabilityRate(); + if ($instanceRisk->getReductionAmount() !== 0) { + $instanceRisk->setReductionAmount($this->convertValueWithinNewScalesRange( + $instanceRisk->getReductionAmount(), + 0, + $oldVulRate, + 0, + $newVulRate, + 0 + )); + } + } + + $this->recalculateRiskRates($instanceRisk); + + $this->instanceRiskTable->save($instanceRisk, false); + } + } + } + } + + public function updateThreatsQualification( + Entity\Anr $anr, + Entity\Scale $currentScale, + array $newScaleImpactData + ): void { + /** @var Entity\Threat $threat */ + foreach ($this->threatTable->findByAnr($anr) as $threat) { + $threat->setQualification($this->convertValueWithinNewScalesRange( + $threat->getQualification(), + $currentScale->getMin(), + $currentScale->getMax(), + $newScaleImpactData['min'], + $newScaleImpactData['max'] + )); + $this->threatTable->save($threat, false); + } + } + + public function getScaleImpactTypeFromCacheByLabel(Entity\Anr $anr, string $typeLabel): ?Entity\ScaleImpactType + { + if (!$this->importCacheHelper->isCacheKeySet('scale_impact_types_by_label')) { + /** @var Entity\ScaleImpactType $scaleImpactType */ + foreach ($this->scaleImpactTypeTable->findByAnrIndexedByType($anr) as $scaleImpactType) { + $this->importCacheHelper->addItemToArrayCache( + 'scale_impact_types_by_label', + $scaleImpactType, + $scaleImpactType->getLabel($anr->getLanguage()) + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('scale_impact_types_by_label', $typeLabel); + } + + /** + * @return Entity\ScaleImpactType[] + */ + public function getScalesImpactTypesFromCache(Entity\Anr $anr): array + { + if (!$this->importCacheHelper->isCacheKeySet('scale_impact_types_by_label')) { + /** @var Entity\ScaleImpactType $scaleImpactType */ + foreach ($this->scaleImpactTypeTable->findByAnrIndexedByType($anr) as $scaleImpactType) { + $this->importCacheHelper->addItemToArrayCache( + 'scale_impact_types_by_label', + $scaleImpactType, + $scaleImpactType->getLabel($anr->getLanguage()) + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('scale_impact_types_by_label'); + } + + public function createNewScaleImpactType( + Entity\Anr $anr, + Entity\Scale $scale, + array $data, + int $existingImpactTypesNumber + ): Entity\ScaleImpactType { + $labelKey = 'label' . $anr->getLanguage(); + if (!isset($data[$labelKey])) { + $data[$labelKey] = $data['label']; + } + + $newScaleImpactType = $this->anrScaleImpactTypeService->create( + $anr, + array_merge($data, ['scale' => $scale, 'type' => ++$existingImpactTypesNumber]), + false + ); + + $this->importCacheHelper->addItemToArrayCache( + 'scale_impact_types_by_label', + $newScaleImpactType, + $data['label'] + ); + + return $newScaleImpactType; + } + + private function applyNewScaleImpactTypesAndComments( + Entity\Anr $anr, + Entity\Scale $scale, + array $newScaleImpactTypesData + ): void { + $existingImpactTypesNumber = 0; + /* Process the existing scales impact types in order to update labels and visibility if necessary. */ + foreach ($scale->getScaleImpactTypes() as $scaleImpactType) { + $typeKey = array_search( + $scaleImpactType->getType(), + array_column($newScaleImpactTypesData, 'type'), + true + ); + if ($scaleImpactType->isSys()) { + if ($typeKey !== false && isset($newScaleImpactTypesData[$typeKey]['label']) && ( + $newScaleImpactTypesData[$typeKey]['label'] !== $scaleImpactType->getLabel($anr->getLanguage()) + || $newScaleImpactTypesData[$typeKey]['isHidden'] !== $scaleImpactType->isHidden() + )) { + /* The current system impact type visibility is changing to hidden, + so all the consequences have to be updated and the risks recalculated if needed. */ + if ($newScaleImpactTypesData[$typeKey]['isHidden'] && !$scaleImpactType->isHidden()) { + $this->validateConsequencesAndRisksForHidingImpactType($scaleImpactType); + } + + $scaleImpactType->setLabels( + ['label' . $anr->getLanguage() => $newScaleImpactTypesData[$typeKey]['label']] + )->setIsHidden($newScaleImpactTypesData[$typeKey]['isHidden']) + ->setUpdater($this->connectedUser->getEmail()); + $this->scaleImpactTypeTable->save($scaleImpactType, false); + } + } + + $this->importCacheHelper->addItemToArrayCache( + 'scale_impact_types_by_label', + $scaleImpactType, + $scaleImpactType->getLabel($anr->getLanguage()) + ); + $existingImpactTypesNumber++; + + if ($typeKey !== false && !empty($newScaleImpactTypesData[$typeKey]['scaleComments'])) { + $this->applyNewScalesImpactsTypesComments( + $anr, + $scaleImpactType, + $newScaleImpactTypesData[$typeKey]['scaleComments'] + ); + } + } + + /* Process the importing scale impact types data. */ + foreach ($newScaleImpactTypesData as $newScaleImpactTypeData) { + if (!$newScaleImpactTypeData['isSys'] && !empty($newScaleImpactTypeData['label'])) { + $existingCustomImpactType = $this + ->getScaleImpactTypeFromCacheByLabel($anr, $newScaleImpactTypeData['label']); + if ($existingCustomImpactType !== null) { + if ($existingCustomImpactType->isHidden() !== $newScaleImpactTypeData['isHidden']) { + if ($newScaleImpactTypesData['isHidden'] && !$existingCustomImpactType->isHidden()) { + $this->validateConsequencesAndRisksForHidingImpactType($existingCustomImpactType); + } + $existingCustomImpactType->setIsHidden($newScaleImpactTypeData['isHidden']) + ->setUpdater($this->connectedUser->getEmail()); + $this->scaleImpactTypeTable->save($existingCustomImpactType, false); + } + } else { + $newScaleImpactType = $this + ->createNewScaleImpactType($anr, $scale, $newScaleImpactTypeData, $existingImpactTypesNumber); + + $this->applyNewScalesImpactsTypesComments( + $anr, + $newScaleImpactType, + $newScaleImpactTypeData['scaleComments'] + ); + } + } + } + } + + private function applyNewScalesImpactsTypesComments( + Entity\Anr $anr, + Entity\ScaleImpactType $scaleImpactType, + array $newScaleCommentsData + ): void { + $langIndex = $anr->getLanguage(); + foreach ($scaleImpactType->getScaleComments() as $existingScaleComment) { + $commentKey = array_search( + $existingScaleComment->getScaleValue(), + array_column($newScaleCommentsData, 'scaleValue'), + true + ); + if ($commentKey !== false) { + if (!empty($newScaleCommentsData[$commentKey]['comment']) + && $existingScaleComment->getComment($langIndex) !== $newScaleCommentsData[$commentKey]['comment'] + ) { + $existingScaleComment->setComments( + ['comment' . $langIndex => $newScaleCommentsData[$commentKey]['comment']] + )->setUpdater($this->connectedUser->getEmail()); + $this->scaleCommentTable->save($existingScaleComment, false); + } + unset($newScaleCommentsData[$commentKey]); + } + } + + foreach ($newScaleCommentsData as $newScaleCommentData) { + $newScaleCommentData['comment' . $langIndex] = $newScaleCommentData['comment']; + $newScaleCommentData['scale'] = $scaleImpactType->getScale(); + $newScaleCommentData['scaleImpactType'] = $scaleImpactType; + $this->anrScaleCommentService->create($anr, $newScaleCommentData, false); + } + } + + private function validateConsequencesAndRisksForHidingImpactType(Entity\ScaleImpactType $hidingImpactType): void + { + foreach ($hidingImpactType->getInstanceConsequences() as $consequence) { + $confidentialityOfHiding = $consequence->getConfidentiality(); + $integrityOfHiding = $consequence->getIntegrity(); + $availabilityOfHiding = $consequence->getAvailability(); + $consequence->setIsHidden(true) + ->setConfidentiality(-1) + ->setIntegrity(-1) + ->setAvailability(-1) + ->setUpdater($this->connectedUser->getEmail()); + $this->instanceConsequenceTable->save($consequence, false); + + if (max($confidentialityOfHiding, $integrityOfHiding, $availabilityOfHiding) !== -1) { + $maxConfidentiality = -1; + $maxIntegrity = -1; + $maxAvailability = -1; + $validatingInstance = $consequence->getInstance(); + foreach ($validatingInstance->getInstanceConsequences() as $consequenceToValidate) { + if ($consequenceToValidate->getId() !== $consequence->getId()) { + $maxConfidentiality = $consequenceToValidate->getConfidentiality() > $maxConfidentiality + ? $consequenceToValidate->getConfidentiality() + : $maxConfidentiality; + $maxIntegrity = $consequenceToValidate->getIntegrity() > $maxIntegrity + ? $consequenceToValidate->getIntegrity() + : $maxIntegrity; + $maxAvailability = $consequenceToValidate->getAvailability() > $maxAvailability + ? $consequenceToValidate->getAvailability() + : $maxAvailability; + } + } + if ($confidentialityOfHiding > $maxConfidentiality + || $integrityOfHiding > $maxIntegrity + || $availabilityOfHiding > $maxAvailability + ) { + /* Recalculate the instances and instance risks values. */ + $validatingInstance->setConfidentiality($maxConfidentiality) + ->setIntegrity($maxIntegrity) + ->setAvailability($maxAvailability) + ->setUpdater($this->connectedUser->getEmail()); + $this->instanceTable->save($validatingInstance, false); + foreach ($validatingInstance->getInstanceRisks() as $validatingInstanceRisk) { + $this->recalculateRiskRates($validatingInstanceRisk); + $validatingInstanceRisk->setUpdater($this->connectedUser->getEmail()); + $this->instanceRiskTable->save($validatingInstanceRisk, false); + } + } + } + } + } +} diff --git a/src/Import/Processor/SoaImportProcessor.php b/src/Import/Processor/SoaImportProcessor.php new file mode 100644 index 00000000..7d9da275 --- /dev/null +++ b/src/Import/Processor/SoaImportProcessor.php @@ -0,0 +1,173 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function processSoasData(Entity\Anr $anr, array $soasData): void + { + foreach ($soasData as $soaData) { + $this->processSoaData($anr, $soaData); + } + } + + public function mergeSoaScaleComments(Entity\Anr $anr, array $newSoaScaleCommentsData): void + { + $currentSoaScaleCommentsNumber = 0; + $newSoaScaleCommentsNumber = \count($newSoaScaleCommentsData); + /** @var Entity\SoaScaleComment $currentSoaScaleComment */ + foreach ($this->soaScaleCommentTable->findByAnrIndexedByScaleIndex($anr) as $currentSoaScaleComment) { + $soaScaleCommentKey = array_search( + $currentSoaScaleComment->getScaleIndex(), + array_column($newSoaScaleCommentsData, 'scaleIndex'), + true + ); + if (!$currentSoaScaleComment->isHidden()) { + $currentSoaScaleCommentsNumber++; + } + if ($soaScaleCommentKey === false && !$currentSoaScaleComment->isHidden()) { + $currentSoaScaleComment->setIsHidden(true); + } elseif ($soaScaleCommentKey !== false) { + $newSoaScaleCommentData = $newSoaScaleCommentsData[$soaScaleCommentKey]; + if ($currentSoaScaleComment->getColour() !== $newSoaScaleCommentData['colour'] || + $currentSoaScaleComment->getComment() !== $newSoaScaleCommentData['comment'] + ) { + $currentSoaScaleComment->setColour($newSoaScaleCommentData['colour']) + ->setComment($newSoaScaleCommentData['comment']) + ->setIsHidden(false) + ->setUpdater($this->connectedUser->getEmail()); + $this->soaScaleCommentTable->save($currentSoaScaleComment, false); + } + $this->importCacheHelper->addItemToArrayCache( + 'soa_scale_comments_by_index', + $currentSoaScaleComment, + $currentSoaScaleComment->getScaleIndex() + ); + } + } + + /* Create new scales if the new comments number is more than current ones. */ + if ($newSoaScaleCommentsNumber > $currentSoaScaleCommentsNumber) { + for ($index = $currentSoaScaleCommentsNumber; $index < $newSoaScaleCommentsNumber; $index++) { + $soaScaleCommentKey = array_search($index, array_column($newSoaScaleCommentsData, 'scaleIndex'), true); + if ($soaScaleCommentKey !== false) { + $newSoaScaleComment = $this->soaScaleCommentService->createSoaScaleComment( + $anr, + $index, + $newSoaScaleCommentsData[$soaScaleCommentKey]['colour'], + $newSoaScaleCommentsData[$soaScaleCommentKey]['comment'] + ); + $this->importCacheHelper + ->addItemToArrayCache('soa_scale_comments_by_index', $newSoaScaleComment, $index); + } + } + } + + /* Adjust the existing SOA's scales comments indexes to the new number of the comments' level. */ + if ($currentSoaScaleCommentsNumber !== $newSoaScaleCommentsNumber) { + $this->adjustSoasWithScaleCommentsChanges( + $anr, + $currentSoaScaleCommentsNumber - 1, + $newSoaScaleCommentsNumber - 1 + ); + } + } + + private function processSoaData(Entity\Anr $anr, array $soaData): Entity\Soa + { + /* Support the old structure field name prior v2.13.1. */ + $measureUuid = $soaData['measure_id'] ?? $soaData['measureUuid']; + /* New SOAs were created and cached during the new measures process, and existed SOA's cache is initialising. */ + $soa = $this->getSoaFromCache($anr, $measureUuid); + if (isset($soaData['soaScaleCommentIndex']) && $soaData['soaScaleCommentIndex'] !== null) { + $soaData['soaScaleComment'] = $this->importCacheHelper + ->getItemFromArrayCache('soa_scale_comments_by_index', $soaData['soaScaleCommentIndex']); + } + if ($soa !== null) { + $this->soaService->patchSoaObject($anr, $soa, $soaData, false); + } else { + $measure = $this->referentialImportProcessor->getMeasureFromCache($anr, $measureUuid); + if ($measure === null) { + throw new \Exception('Measures have to be processed before the Statement of Applicability data.', 412); + } + $soa = $this->soaService->createSoaObject($anr, $measure, $soaData); + } + + return $soa; + } + + private function adjustSoasWithScaleCommentsChanges( + Entity\Anr $anr, + int $currentMaxSoaScaleIndex, + int $newMaxSoaScaleIndex + ): void { + foreach ($this->soaTable->findByAnrWithNotEmptySoaScaleComments($anr) as $soa) { + /** @var Entity\SoaScaleComment $soaComment */ + $soaComment = $soa->getSoaScaleComment(); + $newScaleIndex = $this->convertValueWithinNewScalesRange( + $soaComment->getScaleIndex(), + 0, + $currentMaxSoaScaleIndex, + 0, + $newMaxSoaScaleIndex, + 0 + ); + if ($soaComment->getScaleIndex() !== $newScaleIndex + && $this->importCacheHelper->isItemInArrayCache('soa_scale_comments_by_index', $newScaleIndex) + ) { + $soa->setSoaScaleComment( + $this->importCacheHelper->getItemFromArrayCache('soa_scale_comments_by_index', $newScaleIndex) + ); + $this->soaTable->save($soa, false); + } + } + } + + private function getSoaFromCache(Entity\Anr $anr, string $measureUuid): ?Entity\Soa + { + if (!$this->importCacheHelper->isCacheKeySet('is_soa_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_soa_cache_loaded', true); + /** @var Entity\Soa $soa */ + foreach ($this->soaTable->findByAnr($anr) as $soa) { + $this->importCacheHelper->addItemToArrayCache( + 'soas_by_measure_uuids', + $soa, + $soa->getMeasure()->getUuid() + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('soas_by_measure_uuids', $measureUuid); + } +} diff --git a/src/Import/Processor/ThreatImportProcessor.php b/src/Import/Processor/ThreatImportProcessor.php new file mode 100644 index 00000000..0aba80b2 --- /dev/null +++ b/src/Import/Processor/ThreatImportProcessor.php @@ -0,0 +1,114 @@ +processThreatData($anr, $threatData, $themesData); + } + } + + public function processThreatData(Entity\Anr $anr, array $threatData, array $themesData = []): Entity\Threat + { + $threat = $this->getThreatFromCache($anr, $threatData['uuid']); + if ($threat !== null) { + return $threat; + } + + /* In the old structure themes are exported separately, convert to the new format. */ + $labelKey = 'label' . $anr->getLanguage(); + if (!empty($themesData) + && !empty($threatData['theme']) + && isset($themesData[$threatData['theme']][$labelKey]) + ) { + $threatData['theme'] = ['label' => $themesData[$threatData['theme']][$labelKey]]; + } + + if ($this->importCacheHelper->isItemInArrayCache('threats_codes', $threatData['code'])) { + $threatData['code'] .= '-' . time(); + } + $threatData['theme'] = !empty($threatData['theme']) + ? $this->processThemeData($anr, $threatData['theme']) + : null; + + /* In the new data structure there is only "label" field set. */ + if (isset($threatData['label'])) { + $threatData['label' . $anr->getLanguage()] = $threatData['label']; + } + if (isset($threatData['description'])) { + $threatData['description' . $anr->getLanguage()] = $threatData['description']; + } + + $threat = $this->anrThreatService->create($anr, $threatData, false); + $this->importCacheHelper->addItemToArrayCache('threats_by_uuid', $threat, $threat->getUuid()); + + return $threat; + } + + public function getThreatFromCache(Entity\Anr $anr, string $uuid): ?Entity\Threat + { + if (!$this->importCacheHelper->isCacheKeySet('is_threats_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_threats_cache_loaded', true); + /** @var Entity\Threat $threat */ + foreach ($this->threatTable->findByAnr($anr) as $threat) { + $this->importCacheHelper->addItemToArrayCache('threats_by_uuid', $threat, $threat->getUuid()); + $this->importCacheHelper->addItemToArrayCache('threats_codes', $threat->getCode(), $threat->getCode()); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('threats_by_uuid', $uuid); + } + + private function processThemeData(Entity\Anr $anr, array $themeData): Entity\Theme + { + if (isset($themeData['label'])) { + $themeData['label' . $anr->getLanguage()] = $themeData['label']; + } + $themeLabel = $themeData['label' . $anr->getLanguage()]; + $theme = $this->getThemeFromCache($anr, $themeLabel); + if ($theme === null) { + $theme = $this->anrThemeService->create($anr, $themeData, false); + $this->importCacheHelper->addItemToArrayCache('themes_by_labels', $theme, $themeLabel); + } + + return $theme; + } + + private function getThemeFromCache(Entity\Anr $anr, string $label): ?Entity\Theme + { + if (!$this->importCacheHelper->isCacheKeySet('is_themes_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_themes_cache_loaded', true); + /** @var Entity\Theme $theme */ + foreach ($this->themeTable->findByAnr($anr) as $theme) { + $this->importCacheHelper + ->addItemToArrayCache('themes_by_labels', $theme, $theme->getLabel($anr->getLanguage())); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('themes_by_labels', $label); + } +} diff --git a/src/Import/Processor/VulnerabilityImportProcessor.php b/src/Import/Processor/VulnerabilityImportProcessor.php new file mode 100644 index 00000000..46b9d001 --- /dev/null +++ b/src/Import/Processor/VulnerabilityImportProcessor.php @@ -0,0 +1,76 @@ +processVulnerabilityData($anr, $vulnerabilityData); + } + } + + public function processVulnerabilityData(Entity\Anr $anr, array $vulnerabilityData): Entity\Vulnerability + { + $vulnerability = $this->getVulnerabilityFromCache($anr, $vulnerabilityData['uuid']); + if ($vulnerability !== null) { + return $vulnerability; + } + + /* The code should be unique. */ + if ($this->importCacheHelper->isItemInArrayCache('vulnerabilities_codes', $vulnerabilityData['code'])) { + $vulnerabilityData['code'] .= '-' . time(); + } + + /* In the new data structure there is only "label" field set. */ + if (isset($vulnerabilityData['label'])) { + $vulnerabilityData['label' . $anr->getLanguage()] = $vulnerabilityData['label']; + } + if (isset($vulnerabilityData['description'])) { + $vulnerabilityData['description' . $anr->getLanguage()] = $vulnerabilityData['description']; + } + + $vulnerability = $this->anrVulnerabilityService->create($anr, $vulnerabilityData, false); + $this->importCacheHelper + ->addItemToArrayCache('vulnerabilities_by_uuid', $vulnerability, $vulnerability->getUuid()); + + return $vulnerability; + } + + public function getVulnerabilityFromCache(Entity\Anr $anr, string $uuid): ?Entity\Vulnerability + { + if (!$this->importCacheHelper->isCacheKeySet('is_vulnerabilities_cache_loaded')) { + $this->importCacheHelper->setArrayCacheValue('is_vulnerabilities_cache_loaded', true); + /** @var Entity\Vulnerability $vulnerability */ + foreach ($this->vulnerabilityTable->findByAnr($anr) as $vulnerability) { + $this->importCacheHelper + ->addItemToArrayCache('vulnerabilities_by_uuid', $vulnerability, $vulnerability->getUuid()); + $this->importCacheHelper->addItemToArrayCache( + 'vulnerabilities_codes', + $vulnerability->getCode(), + $vulnerability->getCode() + ); + } + } + + return $this->importCacheHelper->getItemFromArrayCache('vulnerabilities_by_uuid', $uuid); + } +} diff --git a/src/Import/Service/AssetImportService.php b/src/Import/Service/AssetImportService.php deleted file mode 100644 index c1de799d..00000000 --- a/src/Import/Service/AssetImportService.php +++ /dev/null @@ -1,395 +0,0 @@ -assetTable = $assetTable; - $this->themeTable = $themeTable; - $this->threatTable = $threatTable; - $this->vulnerabilityTable = $vulnerabilityTable; - $this->measureTable = $measureTable; - $this->amvTable = $amvTable; - $this->instanceTable = $instanceTable; - $this->instanceRiskTable = $instanceRiskTable; - $this->referentialTable = $referentialTable; - $this->connectedUser = $connectedUserService->getConnectedUser(); - $this->importCacheHelper = $importCacheHelper; - $this->soaCategoryService = $soaCategoryService; - } - - public function importFromArray($monarcVersion, array $data, Anr $anr): ?Asset - { - if (!isset($data['type']) || $data['type'] !== 'asset') { - return null; - } - - if (version_compare($monarcVersion, '2.8.2') < 0) { - throw new Exception('Import of files exported from MONARC v2.8.1 or lower are not supported.' - . ' Please contact us for more details.'); - } - - $asset = $this->processAssetDataAndGetAsset($data['asset'], $anr); - if (!empty($data['amvs'])) { - $this->processThreatsData($data['threats'], $data['themes'] ?? [], $anr); - $this->processVulnerabilitiesData($data['vuls'], $anr); - $this->processAmvsData($data, $anr, $asset); - } - - return $asset; - } - - private function processAssetDataAndGetAsset(array $assetData, Anr $anr): Asset - { - $asset = $this->assetTable->findByAnrAndUuid($anr, $assetData['uuid']); - if ($asset !== null) { - return $asset; - } - - /* The code should be unique. */ - $assetCode = $this->assetTable->existsWithAnrAndCode($anr, $assetData['code']) - ? $assetData['code'] . '-' . time() - : $assetData['code']; - - $asset = (new Asset()) - ->setUuid($assetData['uuid']) - ->setAnr($anr) - ->setLabels($assetData) - ->setDescriptions($assetData) - ->setStatus($assetData['status'] ?? 1) - ->setMode($assetData['mode'] ?? 0) - ->setType($assetData['type']) - ->setCode($assetCode); - - $this->assetTable->saveEntity($asset, false); - - return $asset; - } - - private function processThreatsData(array $threatsData, array $themesData, Anr $anr): void - { - $languageIndex = $anr->getLanguage(); - $labelKey = 'label' . $languageIndex; - - foreach ($threatsData as $threatUuid => $threatData) { - $themeData = $themesData[$threatData['theme']] ?? []; - $threat = $this->threatTable->findByAnrAndUuid($anr, $threatUuid); - if ($threat !== null) { - /* Validate Theme. */ - $currentTheme = $threat->getTheme(); - if (!empty($themeData) - && ($currentTheme === null - || $currentTheme->getLabel($languageIndex) !== $themeData[$labelKey] - ) - ) { - $theme = $this->processThemeDataAndGetTheme($themeData, $anr); - $threat->setTheme($theme); - } - } else { - /* The code should be unique. */ - $threatData['code'] = $this->importCacheHelper - ->getItemFromArrayCache('threats_codes', $threatData['code']) !== null - || $this->threatTable->existsWithAnrAndCode($anr, $threatData['code']) - ? $threatData['code'] . '-' . time() - : $threatData['code']; - - $threat = (new Threat()) - ->setUuid($threatData['uuid']) - ->setAnr($anr) - ->setCode($threatData['code']) - ->setLabels($threatData) - ->setDescriptions($threatData) - ->setMode((int)$threatData['mode']) - ->setStatus((int)$threatData['status']) - ->setTrend((int)$threatData['trend']) - ->setQualification((int)$threatData['qualification']) - ->setComment($threatData['comment'] ?? '') - ->setCreator($this->connectedUser->getEmail()); - if (isset($threatData['c'])) { - $threat->setConfidentiality((int)$threatData['c']); - } - if (isset($threatData['i'])) { - $threat->setIntegrity((int)$threatData['i']); - } - if (isset($threatData['a'])) { - $threat->setAvailability((int)$threatData['a']); - } - if (!empty($themeData)) { - $threat->setTheme($this->processThemeDataAndGetTheme($themeData, $anr)); - } - } - - $this->importCacheHelper->addItemToArrayCache('threats', $threat, $threat->getUuid()); - $this->importCacheHelper->addItemToArrayCache('threats_codes', $threat->getCode(), $threat->getCode()); - - $this->threatTable->saveEntity($threat, false); - } - } - - private function processThemeDataAndGetTheme(array $themeData, Anr $anr): Theme - { - $this->importCacheHelper->prepareThemesCacheData($anr); - - $languageIndex = $anr->getLanguage(); - $labelKey = 'label' . $languageIndex; - $theme = $this->importCacheHelper->getItemFromArrayCache('themes_by_labels', $themeData[$labelKey]); - if ($theme === null) { - $theme = $this->getCreatedTheme($anr, $themeData); - $this->importCacheHelper->addItemToArrayCache('themes_by_labels', $theme, $themeData[$labelKey]); - } - - return $theme; - } - - private function getCreatedTheme(Anr $anr, array $data): Theme - { - $theme = (new Theme()) - ->setAnr($anr) - ->setLabels($data) - ->setCreator($this->connectedUser->getEmail()); - - $this->themeTable->saveEntity($theme); - - return $theme; - } - - private function processVulnerabilitiesData(array $vulnerabilitiesData, Anr $anr): void - { - foreach ($vulnerabilitiesData as $vulnerabilityData) { - $vulnerability = $this->vulnerabilityTable->findByAnrAndUuid($anr, $vulnerabilityData['uuid'], false); - if ($vulnerability === null) { - /* The code should be unique. */ - $vulnerabilityData['code'] = $this->importCacheHelper - ->getItemFromArrayCache('vulnerabilities_codes', $vulnerabilityData['code']) !== null - || $this->vulnerabilityTable->existsWithAnrAndCode($anr, $vulnerabilityData['code']) - ? $vulnerabilityData['code'] . '-' . time() - : $vulnerabilityData['code']; - - $vulnerability = (new Vulnerability()) - ->setUuid($vulnerabilityData['uuid']) - ->setAnr($anr) - ->setLabels($vulnerabilityData) - ->setDescriptions($vulnerabilityData) - ->setCode($vulnerabilityData['code']) - ->setMode($vulnerabilityData['mode']) - ->setStatus($vulnerabilityData['status']) - ->setCreator($this->connectedUser->getEmail()); - - $this->vulnerabilityTable->saveEntity($vulnerability, false); - } - - $this->importCacheHelper->addItemToArrayCache('vulnerabilities', $vulnerability, $vulnerability->getUuid()); - $this->importCacheHelper - ->addItemToArrayCache('vulnerabilities_codes', $vulnerability->getCode(), $vulnerability->getCode()); - } - } - - private function processAmvsData(array $data, Anr $anr, Asset $asset): void - { - $instances = null; - $amvsData = $data['amvs']; - foreach ($amvsData as $amvUuid => $amvData) { - $amv = $this->amvTable->findByAnrAndUuid($anr, $amvUuid); - if ($amv === null) { - $amv = (new Amv()) - ->setUuid($amvUuid) - ->setAnr($anr) - ->setAsset($asset) - ->setMeasures(null) - ->setCreator($this->connectedUser->getEmail()); - - $threat = $this->importCacheHelper->getItemFromArrayCache('threats', $amvData['threat']); - $vulnerability = $this->importCacheHelper - ->getItemFromArrayCache('vulnerabilities', $amvData['vulnerability']); - if ($threat === null || $vulnerability === null) { - throw new Exception(sprintf( - 'The import file is malformed. AMV\'s "%s" threats or vulnerability was not processed before.', - $amvUuid - )); - } - - $amv->setThreat($threat)->setVulnerability($vulnerability); - - $this->amvTable->saveEntity($amv, false); - - if ($instances === null) { - $instances = $this->instanceTable->findByAnrAndAsset($anr, $asset); - } - foreach ($instances as $instance) { - $instanceRisk = (new InstanceRisk()) - ->setAnr($anr) - ->setAmv($amv) - ->setAsset($asset) - ->setInstance($instance) - ->setThreat($threat) - ->setVulnerability($vulnerability) - ->setCreator($this->connectedUser->getEmail()); - - $this->instanceRiskTable->saveEntity($instanceRisk, false); - } - } - - if (!empty($amvData['measures'])) { - $this->processMeasuresAndReferentialData($amvData['measures'], $data['measures'] ?? [], $anr, $amv); - } - } - - foreach ($this->amvTable->findByAnrAndAsset($anr, $asset) as $oldAmv) { - if (!isset($amvsData[$oldAmv->getUuid()])) { - /** Set related instance risks to specific and delete the amvs leter */ - $instanceRisks = $oldAmv->getInstanceRisks(); - - // TODO: remove the double iteration when #240 is done. - // We do it due to multi-fields relation issue. When amv is set to null, anr is set to null as well. - foreach ($instanceRisks as $instanceRisk) { - $instanceRisk->setAmv(null); - $instanceRisk->setAnr(null); - $instanceRisk->setSpecific(InstanceRisk::TYPE_SPECIFIC); - $this->instanceRiskTable->saveEntity($instanceRisk, false); - } - $this->instanceRiskTable->getDb()->flush(); - - foreach ($instanceRisks as $instanceRisk) { - $instanceRisk - ->setAnr($anr) - ->setUpdater($this->connectedUser->getEmail()); - $this->instanceRiskTable->saveEntity($instanceRisk, false); - } - $this->instanceRiskTable->getDb()->flush(); - - $amvsToDelete[] = $oldAmv; - } - } - - if (!empty($amvsToDelete)) { - $this->amvTable->deleteEntities($amvsToDelete); - } elseif (!empty($amvsData)) { - $this->amvTable->getDb()->flush(); - } - } - - private function processMeasuresAndReferentialData( - array $amvMeasuresUuids, - array $measuresData, - Anr $anr, - Amv $amv - ): void { - $languageIndex = $anr->getLanguage(); - $labelKey = 'label' . $languageIndex; - foreach ($amvMeasuresUuids as $measureUuid) { - $measure = $this->importCacheHelper->getItemFromArrayCache('measures', $measureUuid) - ?: $this->measureTable->findByAnrAndUuid($anr, $measureUuid); - if ($measure === null) { - /* Backward compatibility. Prior v2.10.3 we did not set referential data when exported. */ - $referentialUuid = $measuresData[$measureUuid]['referential']['uuid'] - ?? $measuresData[$measureUuid]['referential']; - - $referential = $this->importCacheHelper->getItemFromArrayCache('referentials', $referentialUuid) - ?: $this->referentialTable->findByAnrAndUuid($anr, $referentialUuid); - - /* For backward compatibility. */ - if ($referential === null - && isset($measuresData[$measureUuid]['referential'][$labelKey]) - ) { - $referential = (new Referential()) - ->setAnr($anr) - ->setUuid($referentialUuid) - ->{'setLabel' . $languageIndex}( - $measuresData[$measureUuid]['referential'][$labelKey] - ) - ->setCreator($this->connectedUser->getEmail()); - - $this->referentialTable->saveEntity($referential, false); - - $this->importCacheHelper->addItemToArrayCache('referentials', $referential, $referentialUuid); - } - - /* For backward compatibility. */ - if ($referential === null) { - continue; - } - - $soaCategory = $this->soaCategoryService->getOrCreateSoaCategory( - $this->importCacheHelper, - $anr, - $referential, - $measuresData[$measureUuid]['category'][$labelKey] ?? '' - ); - - $measure = (new Measure()) - ->setAnr($anr) - ->setUuid($measureUuid) - ->setCategory($soaCategory) - ->setReferential($referential) - ->setCode($measuresData[$measureUuid]['code']) - ->setLabels($measuresData[$measureUuid]) - ->setCreator($this->connectedUser->getEmail()); - - $this->importCacheHelper->addItemToArrayCache('measures', $measure, $measure->getUuid()); - } - - $measure->addAmv($amv); - - $this->measureTable->saveEntity($measure, false); - } - } -} diff --git a/src/Import/Service/InstanceImportService.php b/src/Import/Service/InstanceImportService.php index a3c685ee..4c5c1d35 100755 --- a/src/Import/Service/InstanceImportService.php +++ b/src/Import/Service/InstanceImportService.php @@ -1,3187 +1,339 @@ anrInstanceRiskService = $anrInstanceRiskService; - $this->anrInstanceService = $anrInstanceService; - $this->objectImportService = $objectImportService; - $this->anrRecordService = $anrRecordService; - $this->anrInstanceRiskOpService = $anrInstanceRiskOpService; - $this->instanceTable = $instanceTable; - $this->anrTable = $anrTable; - $this->instanceConsequenceTable = $instanceConsequenceTable; - $this->scaleTable = $scaleTable; - $this->threatTable = $threatTable; - $this->vulnerabilityTable = $vulnerabilityTable; - $this->recommendationTable = $recommendationTable; - $this->recommendationSetTable = $recommendationSetTable; - $this->instanceRiskTable = $instanceRiskTable; - $this->instanceRiskOpTable = $instanceRiskOpTable; - $this->recommendationRiskTable = $recommendationRiskTable; - $this->questionTable = $questionTable; - $this->questionChoiceTable = $questionChoiceTable; - $this->soaTable = $soaTable; - $this->measureTable = $measureTable; - $this->measureMeasureTable = $measureMeasureTable; - $this->themeTable = $themeTable; - $this->referentialTable = $referentialTable; - $this->interviewTable = $interviewTable; - $this->deliveryTable = $deliveryTable; - $this->scaleImpactTypeTable = $scaleImpactTypeTable; - $this->scaleCommentTable = $scaleCommentTable; - $this->operationalRiskScaleTable = $operationalRiskScaleTable; - $this->operationalInstanceRiskScaleTable = $operationalInstanceRiskScaleTable; - $this->connectedUser = $connectedUserService->getConnectedUser(); - $this->operationalRiskScaleTypeTable = $operationalRiskScaleTypeTable; - $this->translationTable = $translationTable; - $this->anrMetadatasOnInstancesTable = $anrMetadatasOnInstancesTable; - $this->instanceMetadataTable = $instanceMetadataTable; - $this->soaScaleCommentTable = $soaScaleCommentTable; - $this->configService = $configService; - $this->operationalRiskScaleCommentTable = $operationalRiskScaleCommentTable; - $this->importCacheHelper = $importCacheHelper; - $this->soaCategoryService = $soaCategoryService; - } - - public function cleanCache(): void - { - $this->cachedData = []; - $this->importCacheHelper->cleanArrayCache(); } - /** + /** * Available import modes: 'merge', which will update the existing instances using the file's data, * or 'duplicate' which will create a new instance using the data. * * @return array An array where the first key is the generated IDs, and the second are import errors */ - public function importFromFile(int $anrId, array $data): array + public function importFromFile(Entity\Anr $anr, array $importParams): array { // Mode may either be 'merge' or 'duplicate' - $mode = empty($data['mode']) ? 'merge' : $data['mode']; + $mode = empty($importParams['mode']) ? 'merge' : $importParams['mode']; /* * The object may be imported at the root, or under an existing instance in the ANR instances tree */ $parentInstance = null; - if (!empty($data['idparent'])) { - $parentInstance = $this->instanceTable->findById((int)$data['idparent']); + if (!empty($importParams['idparent'])) { + /** @var Entity\Instance $parentInstance */ + $parentInstance = $this->instanceTable->findById((int)$importParams['idparent']); } // We can have multiple files imported with the same password (we'll emit warnings if the password mismatches) - if (empty($data['file'])) { + if (empty($importParams['file'])) { throw new Exception('File missing', 412); } - $ids = []; - $errors = []; - $anr = $this->anrTable->findById($anrId); - - // TODO: remove this!!! - ini_set('max_execution_time', '0'); - ini_set('memory_limit', '-1'); + $createdInstancesIds = []; + $importErrors = []; + foreach ($importParams['file'] as $file) { + if (isset($file['error']) && $file['error'] === UPLOAD_ERR_OK && file_exists($file['tmp_name'])) { + $data = $this->getArrayDataOfJsonFileContent($file['tmp_name'], $importParams['password'] ?? null); - foreach ($data['file'] as $keyfile => $f) { - // Ensure the file has been uploaded properly, silently skip the files that are erroneous - if (isset($f['error']) && $f['error'] === UPLOAD_ERR_OK && file_exists($f['tmp_name'])) { - if (empty($data['password'])) { - $file = json_decode(trim(file_get_contents($f['tmp_name'])), true, 512, JSON_THROW_ON_ERROR); + if ($data !== false) { + $createdInstancesIds = $this->importFromArray($data, $anr, $parentInstance, $mode); } else { - $key = $data['password']; - $decryptedResult = $this->decrypt(file_get_contents($f['tmp_name']), $key); - if ($decryptedResult === false) { - throw new Exception('Password is not correct.', 412); - } - $file = json_decode(trim($decryptedResult), true, 512, JSON_THROW_ON_ERROR); - unset($decryptedResult); - } - - if ($file !== false - && ($id = $this->importFromArray($file, $anr, $parentInstance, $mode)) !== false) { - // Import was successful, store the ID - if (is_array($id)) { - $ids += array_merge($ids, $id); - } else { - $ids[] = $id; - } - } else { - $errors[] = 'The file "' . $f['name'] . '" can\'t be imported'; + $importErrors[] = 'The file "' . $file['name'] . '" can\'t be imported'; } } - - // Free up the memory in case we're handling big files - unset($data['file'][$keyfile]); } - return [$ids, $errors]; + return [$createdInstancesIds, $importErrors]; } /** - * Imports an instance from an exported data (json) array. + * @param null|Entity\Instance $parentInstance The parent instance, that should be imported, null if it's root. + * @param string $importMode Import mode, either 'merge' or 'duplicate' * - * @param array $data The instance data - * @param Anr $anr The target ANR - * @param null|InstanceSuperClass $parentInstance which should be imported or null if it is root. - * @param string $modeImport Import mode, either 'merge' or 'duplicate' - * - * @return array|bool An array of created instances IDs, or false in case of error + * @return array An array of created instances IDs */ - public function importFromArray( + private function importFromArray( array $data, - Anr $anr, - ?InstanceSuperClass $parentInstance = null, - string $modeImport = 'merge' - ) { + Entity\Anr $anr, + ?Entity\Instance $parentInstance, + string $importMode + ): array { + $this->setAndValidateImportingDataVersion($data); $this->validateIfImportIsPossible($anr, $parentInstance, $data); - $this->setAndValidateMonarcVersion($data); - - $this->currentAnalyseMaxRecommendationPosition = $this->recommendationTable->getMaxPositionByAnr($anr); - $this->currentMaxInstancePosition = $this->instanceTable->getMaxPositionByAnrAndParent($anr, $parentInstance); + $withEval = $data['withEval'] ?? $data['with_eval']; + /* To simplify the value access across all the processors. */ + $this->importCacheHelper->setArrayCacheValue('with_eval', $withEval); - $result = false; + $createdInstances = []; - if (isset($data['type']) && $data['type'] === 'instance') { - $this->importType = 'instance'; - - $result = $this->importInstanceFromArray($data, $anr, $parentInstance, $modeImport); + if ($data['type'] === self::IMPORT_TYPE_ANR) { + $this->importCacheHelper->setArrayCacheValue('import_type', self::IMPORT_TYPE_ANR); + $createdInstances = $this->isImportingDataVersionLowerThan('2.13.1') + ? $this->importAnrFromArray($data, $anr, $parentInstance, $importMode) + : $this->processAnrImport($anr, $data, $parentInstance, $importMode); + } elseif ($data['type'] === self::IMPORT_TYPE_INSTANCE) { + $this->importCacheHelper->setArrayCacheValue('import_type', self::IMPORT_TYPE_INSTANCE); + if ($withEval) { + $this->scaleImportProcessor->prepareScalesCache($anr, $data['scales']); + $this->operationalRiskScaleImportProcessor->prepareExternalOperationalRiskScalesDataCache($anr, $data); + } + if ($this->isImportingDataVersionLowerThan('2.13.1')) { + $data['instance'] = $this->adaptOldInstanceDataToNewFormat($data, $anr->getLanguage()); + } + $createdInstances[] = $this->instanceImportProcessor + ->processInstanceData($anr, $data['instance'], $parentInstance, $importMode); } - if (isset($data['type']) && $data['type'] === 'anr') { - $this->importType = 'anr'; + $this->anrTable->flush(); - $result = $this->importAnrFromArray($data, $anr, $parentInstance, $modeImport); + $result = []; + foreach ($createdInstances as $instance) { + $result[] = $instance->getId(); } return $result; } - private function isImportTypeAnr(): bool - { - return $this->importType === 'anr'; - } - - /** - * @param array $data - * @param Anr $anr - * @param InstanceSuperClass|null $parentInstance - * @param string $modeImport - * - * @return bool|int - */ - private function importInstanceFromArray( + /** New structure full analysis import process, from v2.13.1. */ + private function processAnrImport( + Entity\Anr $anr, array $data, - Anr $anr, - ?InstanceSuperClass $parentInstance, - string $modeImport - ) { - $monarcObject = $this->objectImportService->importFromArray($data['object'], $anr, $modeImport); - if ($monarcObject === null) { - return false; + ?Entity\Instance $parentInstance, + string $importMode + ): array { + if ($data['withMethodSteps']) { + /* Process all the method's steps. */ + $this->anrMethodStepImportProcessor->processAnrMethodStepsData($anr, $data['method']); } + if ($data['withEval']) { + /* Process all the analysis' thresholds. */ + $this->anrMethodStepImportProcessor->processThresholdsData($anr, $data['thresholds']); - $instance = $this->createInstance($data, $anr, $parentInstance, $monarcObject); - - $this->anrInstanceRiskService->createInstanceRisks($instance, $anr, $monarcObject, $data); - - $this->createInstanceMetadata($instance, $data); - - $includeEval = !empty($data['with_eval']); - - $this->prepareInstanceConsequences($data, $anr, $instance, $monarcObject, $includeEval); + /* Apply the importing information risks scales. */ + $this->scaleImportProcessor->applyNewScalesFromData($anr, $data['scales']); - $this->updateInstanceImpactsFromBrothers($instance, $modeImport); - - $this->anrInstanceService->refreshImpactsInherited($instance); - - $this->createSetOfRecommendations($data, $anr); + /* Apply the importing operational risks scales. */ + $this->operationalRiskScaleImportProcessor->adjustOperationalRisksScaleValuesBasedOnNewScales($anr, $data); + $this->operationalRiskScaleImportProcessor->updateOperationalRisksScalesAndRelatedInstances($anr, $data); + } + if (!empty($data['interviews'])) { + /* Process the interviews' data. */ + $this->anrMethodStepImportProcessor->processInterviewsData($anr, $data['interviews']); + } + if (!empty($data['knowledgeBase'])) { + /* Process the Knowledge Base data. */ + $this->processKnowledgeBaseData($anr, $data['knowledgeBase']); + } + if (!empty($data['library'])) { + /* Process the Assets Library data. */ + $this->objectCategoryImportProcessor + ->processObjectCategoriesData($anr, $data['library']['categories'], $importMode); + } + /* Process the analysis metadata fields data. */ + $this->anrInstanceMetadataFieldImportProcessor->processAnrInstanceMetadataFields( + $anr, + $data['anrInstanceMetadataFields'] + ); - $this->processInstanceRisks($data, $anr, $instance, $monarcObject, $includeEval, $modeImport); + /* Process the Instances, Instance Risks, Consequences and evaluations data. */ + $result = $this->instanceImportProcessor + ->processInstancesData($anr, $data['instances'], $parentInstance, $importMode); - $this->processOperationalInstanceRisks($data, $anr, $instance, $monarcObject, $includeEval); + /* Process Soa and SoaScaleComments data. */ + if (!empty($data['soaScaleComments'])) { + $this->soaImportProcessor->mergeSoaScaleComments($anr, $data['soaScaleComments']); + } + if (!empty($data['soas'])) { + $this->soaImportProcessor->processSoasData($anr, $data['soas']); + } - if (!empty($data['children'])) { - usort($data['children'], function ($a, $b) { - return $a['instance']['position'] <=> $b['instance']['position']; - }); - foreach ($data['children'] as $child) { - if ($data['with_eval'] && isset($data['scales'])) { - $child['with_eval'] = $data['with_eval']; - $child['scales'] = $data['scales']; - if (isset($data['operationalRiskScales'])) { - $child['operationalRiskScales'] = $data['operationalRiskScales']; - } - } - $this->importInstanceFromArray($child, $anr, $instance, $modeImport); + /* import the GDPR records. */ + foreach ($data['gdprRecords'] ?? [] as $gdprRecordData) { + try { + $this->anrRecordService->importFromArray($gdprRecordData, $anr->getId()); + } catch (\Throwable) { } - $this->anrInstanceService->updateChildrenImpacts($instance); } - $this->instanceTable->getDb()->flush(); + // TODO: add recommendationHistory to the export and process them. + + return $result; + } - return $instance->getId(); + private function processKnowledgeBaseData(Entity\Anr $anr, array $knowledgeBaseData): void + { + $this->assetImportProcessor->processAssetsData($anr, $knowledgeBaseData['assets']); + $this->threatImportProcessor->processThreatsData($anr, $knowledgeBaseData['threats']); + $this->vulnerabilityImportProcessor->processVulnerabilitiesData($anr, $knowledgeBaseData['vulnerabilities']); + $this->referentialImportProcessor->processReferentialsData($anr, $knowledgeBaseData['referentials']); + $this->informationRiskImportProcessor->processInformationRisksData( + $anr, + $knowledgeBaseData['informationRisks'] + ); + $this->rolfTagImportProcessor->processRolfTagsData($anr, $knowledgeBaseData['rolfTags']); + $this->operationalRiskImportProcessor->processOperationalRisksData( + $anr, + $knowledgeBaseData['operationalRisks'] + ); + $this->recommendationImportProcessor->processRecommendationSetsData( + $anr, + $knowledgeBaseData['recommendationSets'] + ); } /** - * TODO: refactor the method entirely. + * Supports the import data structure prior v2.13.1. + * + * @return Entity\Instance[] */ private function importAnrFromArray( array $data, - Anr $anr, - ?InstanceSuperClass $parentInstance, + Entity\Anr $anr, + ?Entity\Instance $parentInstance, string $modeImport ): array { - $labelKey = 'label' . $anr->getLanguage(); - - // Method information - if (!empty($data['method'])) { //Steps checkboxes - if (!empty($data['method']['steps'])) { - foreach ($data['method']['steps'] as $key => $v) { - if ($anr->get($key) === 0) { - $anr->set($key, $v); - $this->anrTable->saveEntity($anr, false); - } - } - $this->anrTable->getDb()->flush(); - } - - if (!empty($data['method']['data'])) { //Data of textboxes - foreach ($data['method']['data'] as $key => $v) { - if ($anr->get($key) === null) { - $anr->set($key, $v); - $this->anrTable->saveEntity($anr, false); - } - } - $this->anrTable->getDb()->flush(); - } - - if (!empty($data['method']['interviews'])) { //Data of interviews - foreach ($data['method']['interviews'] as $key => $v) { - $toExchange = $data['method']['interviews'][$key]; - $toExchange['anr'] = $anr->getId(); - $newInterview = new Interview(); - $newInterview->setLanguage($anr->getLanguage()); - $newInterview->exchangeArray($toExchange); - $newInterview->setAnr($anr); - // TODO: saveEntity - $this->interviewTable->save($newInterview, false); - } - $this->interviewTable->getDb()->flush(); - } - - if (!empty($data['method']['thresholds'])) { // Value of thresholds - foreach ($data['method']['thresholds'] as $key => $v) { - $anr->set($key, $v); - $this->anrTable->saveEntity($anr, false); - } - $this->anrTable->getDb()->flush(); - } - - if (!empty($data['method']['deliveries'])) { // Data of deliveries generation - foreach ($data['method']['deliveries'] as $key => $v) { - $toExchange = $data['method']['deliveries'][$key]; - $toExchange['anr'] = $anr->getId(); - $newDelivery = new Delivery(); - $newDelivery->setLanguage($anr->getLanguage()); - $newDelivery->exchangeArray($toExchange); - $newDelivery->setAnr($anr); - // TODO: use saveEntity. - $this->deliveryTable->save($newDelivery, false); - } - $this->deliveryTable->getDb()->flush(); - } - - if (!empty($data['method']['questions'])) { // Questions of trends evaluation - // TODO: findByAnr - $questions = $this->questionTable->getEntityByFields(['anr' => $anr->getId()]); - foreach ($questions as $question) { - $this->questionTable->delete($question->id); - } - - foreach ($data['method']['questions'] as $position => $questionData) { - $newQuestion = new Question(); - $newQuestion->setLanguage($anr->getLanguage()); - $newQuestion->exchangeArray($questionData); - $newQuestion->setAnr($anr); - // TODO: use setter. - $newQuestion->set('position', $position); - $this->questionTable->save($newQuestion, false); - - if ((int)$questionData['multichoice'] === 1) { - foreach ($data['method']['questionChoice'] as $questionChoiceData) { - if ($questionChoiceData['question'] === $questionData['id']) { - $newQuestionChoice = new QuestionChoice(); - $newQuestionChoice->setLanguage($anr->getLanguage()); - $newQuestionChoice->exchangeArray($questionChoiceData); - $newQuestionChoice->setAnr($anr) - ->setQuestion($newQuestion); - $this->questionChoiceTable->save($newQuestionChoice, false); - } - } - } - } - - $this->questionTable->getDb()->flush(); - - /** @var Question[] $questions */ - // TODO: findByAnr or better use the saved questions before, we don't need to query the db. - $questions = $this->questionTable->getEntityByFields(['anr' => $anr->getId()]); - - /** @var QuestionChoice[] $questionChoices */ - // TODO: findByAnr or better use the saved questions before, we don't need to query the db. - $questionChoices = $this->questionChoiceTable->getEntityByFields(['anr' => $anr->getId()]); - - foreach ($data['method']['questions'] as $questionAnswerData) { - foreach ($questions as $question) { - if ($question->get($labelKey) === $questionAnswerData[$labelKey]) { - // TODO: check if the method exists - if ($question->isMultiChoice()) { - $originQuestionChoices = []; - $response = $questionAnswerData['response'] ?? ''; - if (trim($response, '[]')) { - $originQuestionChoices = explode(',', trim($response, '[]')); - } - $questionChoicesIds = []; - foreach ($originQuestionChoices as $originQuestionChoice) { - $chosenQuestionLabel = - $data['method']['questionChoice'][$originQuestionChoice][$labelKey] ?? ''; - foreach ($questionChoices as $questionChoice) { - if ($questionChoice->get($labelKey) === $chosenQuestionLabel) { - $questionChoicesIds[] = $questionChoice->getId(); - } - } - } - $question->response = '[' . implode(',', $questionChoicesIds) . ']'; - } else { - $question->response = $questionAnswerData['response']; - } - // TODO: saveEntity. - $this->questionTable->save($question, false); - } - } - } - - $this->questionTable->getDb()->flush(); - } - - /* Process the evaluation of threats. */ - if (!empty($data['method']['threats'])) { - $this->importCacheHelper->prepareThemesCacheData($anr); - foreach ($data['method']['threats'] as $threatUuid => $threatData) { - $threat = $this->importCacheHelper->getItemFromArrayCache('threats', $threatUuid) - ?: $this->threatTable->findByAnrAndUuid($anr, $threatUuid); - if ($threat === null) { - $threatData = $data['method']['threats'][$threatUuid]; - - /* The code should be unique. */ - $threatData['code'] = $this->importCacheHelper - ->getItemFromArrayCache('threats_codes', $threatData['code']) !== null - || $this->threatTable->existsWithAnrAndCode($anr, $threatData['code']) - ? $threatData['code'] . '-' . time() - : $threatData['code']; - - $threat = (new Threat()) - ->setUuid($threatData['uuid']) - ->setAnr($anr) - ->setCode($threatData['code']) - ->setLabels($threatData) - ->setDescriptions($threatData); - if (isset($threatData['c'])) { - $threat->setConfidentiality((int)$threatData['c']); - } - if (isset($threatData['i'])) { - $threat->setIntegrity((int)$threatData['i']); - } - if (isset($threatData['a'])) { - $threat->setAvailability((int)$threatData['a']); - } - - if (!empty($data['method']['threats'][$threatUuid]['theme'])) { - $themeData = $data['method']['threats'][$threatUuid]['theme']; - $labelValue = $themeData[$labelKey]; - $theme = $this->importCacheHelper->getItemFromArrayCache('themes_by_labels', $labelValue); - if ($theme === null) { - $theme = (new Theme()) - ->setAnr($anr) - ->setLabels($themeData) - ->setCreator($this->connectedUser->getEmail()); - - $this->themeTable->saveEntity($theme, false); - $this->importCacheHelper->addItemToArrayCache('themes_by_labels', $theme, $labelValue); - } - - $threat->setTheme($theme); - } - } - - $threat->setTrend((int)$data['method']['threats'][$threatUuid]['trend']); - $threat->setComment((string)$data['method']['threats'][$threatUuid]['comment']); - $threat->setQualification((int)$data['method']['threats'][$threatUuid]['qualification']); - - $this->threatTable->saveEntity($threat, false); - - $this->importCacheHelper->addItemToArrayCache('threats', $threat, $threat->getUuid()); - $this->importCacheHelper - ->addItemToArrayCache('threats_codes', $threat->getCode(), $threat->getCode()); - } - } + /* Import the method steps. */ + if (!empty($data['method'])) { + $this->anrMethodStepImportProcessor->processAnrMethodStepsData($anr, $data['method']); } - /* Import the referentials. */ + /* Import referential. */ if (!empty($data['referentials'])) { - foreach ($data['referentials'] as $referentialUuid => $referentialData) { - $referential = $this->importCacheHelper->getItemFromArrayCache('referentials', $referentialUuid) - ?: $this->referentialTable->findByAnrAndUuid($anr, $referentialUuid); - if ($referential === null) { - $referential = (new Referential($referentialData)) - ->setUuid($referentialUuid) - ->setAnr($anr) - ->setCreator($this->connectedUser->getEmail()); - - $this->referentialTable->saveEntity($referential, false); - } - - $this->importCacheHelper->addItemToArrayCache('referentials', $referential, $referentialUuid); - } + $this->referentialImportProcessor->processReferentialsData($anr, $data['referentials']); } - /* - * Import the soa categories. - */ - if (!empty($data['soacategories'])) { - foreach ($data['soacategories'] as $soaCategoryData) { - $referential = $this->importCacheHelper - ->getItemFromArrayCache('referentials', $soaCategoryData['referential']); - if ($referential !== null) { - $this->soaCategoryService->getOrCreateSoaCategory( - $this->importCacheHelper, - $anr, - $referential, - $soaCategoryData[$labelKey] - ); - } + /* Import measures and soa categories. */ + foreach ($data['measures'] ?? [] as $measureData) { + $referential = $this->referentialImportProcessor->getReferentialFromCache( + $anr, + $measureData['referential'] + ); + if ($referential !== null) { + $this->referentialImportProcessor->processMeasureData($anr, $referential, $measureData); } } - /* - * Import the measures. - */ - if (isset($data['measures'])) { - foreach ($data['measures'] as $measureUuid => $measureData) { - $measure = $this->importCacheHelper->getItemFromArrayCache('measures', $measureUuid) - ?: $this->measureTable->findByAnrAndUuid($anr, $measureUuid); - $referential = $this->importCacheHelper - ->getItemFromArrayCache('referentials', $measureData['referential']); - if ($measure === null && $referential !== null) { - /** @var SoaCategory|null $soaCategory */ - $soaCategory = $this->soaCategoryService->getOrCreateSoaCategory( - $this->importCacheHelper, - $anr, - $referential, - $measureData['category'] - ); - - $measure = (new Measure($measureData)) - ->setUuid($measureUuid) - ->setAnr($anr) - ->setReferential($referential) - ->setCategory($soaCategory) - ->setAmvs(new ArrayCollection()) // need to initialize the amvs link - ->setRolfRisks(new ArrayCollection()) - ->setCreator($this->connectedUser->getEmail()); - - $this->measureTable->saveEntity($measure, false); - - $this->importCacheHelper->addItemToArrayCache('measures', $measure, $measureUuid); - - if (!isset($data['soas'])) { - // if no SOAs in the analysis to import, create new ones - $newSoa = (new Soa()) - ->setAnr($anr) - ->setMeasure($measure); - - $this->soaTable->saveEntity($newSoa, false); - } - } - } - - $this->measureTable->getDb()->flush(); - } - // import the measuresmeasures - if (isset($data['measuresMeasures'])) { - foreach ($data['measuresMeasures'] as $measureMeasureData) { - $measuresMeasures = $this->measureMeasureTable->findByAnrFatherUuidAndChildUuid( + foreach ($data['measuresMeasures'] ?? [] as $measureMeasureData) { + $measure = $this->referentialImportProcessor->getMeasureFromCache($anr, $measureMeasureData['father']); + if ($measure !== null) { + $this->referentialImportProcessor->processLinkedMeasures( $anr, - $measureMeasureData['father'], - $measureMeasureData['child'] + $measure, + ['linkedMeasures' => [['uuid' => $measureMeasureData['child']]]] ); - if ($measuresMeasures === null) { - $measureMeasure = (new MeasureMeasure()) - ->setAnr($anr) - ->setFather($measureMeasureData['father']) - ->setChild($measureMeasureData['child']); - - $this->measureMeasureTable->saveEntity($measureMeasure, false); - } } - $this->measureMeasureTable->getDb()->flush(); } - // import soaScaleComment - $maxOrig = null; //used below for soas - $maxDest = null; //used below for soas - if (isset($data['soaScaleComment'])) { - $oldSoaScaleCommentData = $this->getCurrentSoaScaleCommentData($anr); - $maxDest = \count($oldSoaScaleCommentData) - 1; - $maxOrig = \count($data['soaScaleComment']) - 1; - $this->mergeSoaScaleComment($data['soaScaleComment'], $anr); - } elseif (!isset($data['soaScaleComment']) && isset($data['soas'])) { - //old import case - $defaultSoaScaleCommentdatas = [ - 'fr' => [ - ['scaleIndex' => 0, 'colour' => '#FFFFFF', 'isHidden' => false, 'comment' => 'Inexistant'], - ['scaleIndex' => 1, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Initialisé'], - ['scaleIndex' => 2, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Reproductible'], - ['scaleIndex' => 3, 'colour' => '#FFBC1C', 'isHidden' => false, 'comment' => 'Défini'], - ['scaleIndex' => 4, 'colour' => '#FFBC1C', 'isHidden' => false, - 'comment' => 'Géré quantitativement'], - ['scaleIndex' => 5, 'colour' => '#D6F107', 'isHidden' => false, 'comment' => 'Optimisé'], - ], - 'en' => [ - ['scaleIndex' => 0, 'colour' => '#FFFFFF', 'isHidden' => false, 'comment' => 'Non-existent'], - ['scaleIndex' => 1, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Initial'], - ['scaleIndex' => 2, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Managed'], - ['scaleIndex' => 3, 'colour' => '#FFBC1C', 'isHidden' => false, 'comment' => 'Defined'], - ['scaleIndex' => 4, 'colour' => '#FFBC1C', 'isHidden' => false, - 'comment' => 'Quantitatively managed'], - ['scaleIndex' => 5, 'colour' => '#D6F107', 'isHidden' => false, 'comment' => 'Optimized'], - ], - 'de' => [ - ['scaleIndex' => 0, 'colour' => '#FFFFFF', 'isHidden' => false, 'comment' => 'Nicht vorhanden'], - ['scaleIndex' => 1, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Initial'], - ['scaleIndex' => 2, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Reproduzierbar'], - ['scaleIndex' => 3, 'colour' => '#FFBC1C', 'isHidden' => false, 'comment' => 'Definiert'], - ['scaleIndex' => 4, 'colour' => '#FFBC1C', 'isHidden' => false, - 'comment' => 'Quantitativ verwaltet'], - ['scaleIndex' => 5, 'colour' => '#D6F107', 'isHidden' => false, 'comment' => 'Optimiert'], - ], - 'nl' => [ - ['scaleIndex' => 0, 'colour' => '#FFFFFF', 'isHidden' => false, 'comment' => 'Onbestaand'], - ['scaleIndex' => 1, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Initieel'], - ['scaleIndex' => 2, 'colour' => '#FD661F', 'isHidden' => false, 'comment' => 'Beheerst'], - ['scaleIndex' => 3, 'colour' => '#FFBC1C', 'isHidden' => false, 'comment' => 'Gedefinieerd'], - ['scaleIndex' => 4, 'colour' => '#FFBC1C', 'isHidden' => false, - 'comment' => 'Kwantitatief beheerst'], - ['scaleIndex' => 5, 'colour' => '#D6F107', 'isHidden' => false, 'comment' => 'Optimaliserend'], - ], - ]; - $data['soaScaleComment'] = - $defaultSoaScaleCommentdatas[$this->getAnrLanguageCode($anr)] ?? $defaultSoaScaleCommentdatas['en']; - $oldSoaScaleCommentData = $this->getCurrentSoaScaleCommentData($anr); - $this->mergeSoaScaleComment($data['soaScaleComment'], $anr); - $maxOrig = 5; // default value for old import - $maxDest = \count($oldSoaScaleCommentData) - 1; - } - // manage the current SOA - if ($maxDest !== null && $maxOrig !== null) { - $existedSoas = $this->soaTable->findByAnr($anr); - foreach ($existedSoas as $existedSoa) { - $soaComment = $existedSoa->getSoaScaleComment(); - if ($soaComment !== null) { - $valueToApprox = $soaComment->getScaleIndex(); - $newScaleIndex = $this->approximate( - $valueToApprox, - 0, - $maxDest, - 0, - $maxOrig, - 0 - ); - $soaScaleComment = $this->importCacheHelper - ->getItemFromArrayCache('newSoaScaleCommentIndexedByScale', $newScaleIndex); - if ($soaScaleComment !== null) { - $existedSoa->setSoaScaleComment($soaScaleComment); - } - $this->soaTable->saveEntity($existedSoa, false); - } - } + /* Import SOA Scale Comments if they are passed. Only in the new structure, when the functionality exists. */ + if (!empty($data['soaScaleComment'])) { + $soaScaleCommentsData = $this->adaptOldSoaScaleCommentsToNewFormat($data['soaScaleComment']); + $this->soaImportProcessor->mergeSoaScaleComments($anr, $soaScaleCommentsData); } - // import the SOAs - if (isset($data['soas'])) { - foreach ($data['soas'] as $soaData) { - $measure = $this->importCacheHelper->getItemFromArrayCache('measures', $soaData['measure_id']) - ?: $this->measureTable->findByAnrAndUuid($anr, $soaData['measure_id']); - if ($measure !== null) { - $soa = $this->soaTable->findByAnrAndMeasureUuid($anr, $soaData['measure_id']); - if ($soa === null) { - $soa = (new Soa($soaData)) - ->setAnr($anr) - ->setMeasure($measure); - } else { - $soa->setRemarks($soaData['remarks']) - ->setEvidences($soaData['evidences']) - ->setActions($soaData['actions']) - ->setEX($soaData['EX']) - ->setLR($soaData['LR']) - ->setCO($soaData['CO']) - ->setBR($soaData['BR']) - ->setBP($soaData['BP']) - ->setRRA($soaData['RRA']); - } - if (isset($soaData['soaScaleComment'])) { - $soaScaleComment = $this->importCacheHelper->getItemFromArrayCache( - 'soaScaleCommentExternalIdMapToNewObject', - $soaData['soaScaleComment'] - ); - if ($soaScaleComment !== null) { - $soa->setSoaScaleComment($soaScaleComment); - } - } - $this->soaTable->saveEntity($soa, false); - } + /* Import the Statement of Applicability (SOA). */ + if (!empty($data['soas'])) { + if (!empty($data['soaScaleComment'])) { + $data['soas'] = $this->adaptOldSoasToNewFormatWithSoaScaleCommentIndex($data); } - - $this->soaTable->getDb()->flush(); + $this->soaImportProcessor->processSoasData($anr, $data['soas']); } - // import the GDPR records - if (!empty($data['records'])) { //Data of records + /* Import the GDPR records. */ + if (!empty($data['records'])) { foreach ($data['records'] as $v) { $this->anrRecordService->importFromArray($v, $anr->getId()); } } - /* - * Import AnrMetadatasOnInstances - */ - if (!empty($data['anrMetadataOnInstances'])) { - $this->cachedData['anrMetadataOnInstances'] = $this->getCurrentAnrMetadataOnInstances($anr); - $this->createAnrMetadataOnInstances($anr, $data['anrMetadataOnInstances']); + /* Import AnrInstanceMetadataFields. */ + if (!empty($data['anrMetadatasOnInstances'])) { + $this->anrInstanceMetadataFieldImportProcessor->processAnrInstanceMetadataFields( + $anr, + $data['anrMetadatasOnInstances'] + ); } - /* - * Import scales. - */ - if (!empty($data['scales'])) { - /* Approximate values based on the scales from the destination analysis */ - - $scalesData = $this->getCurrentAndExternalScalesData($anr, $data); - - $ts = ['c', 'i', 'd']; - $instances = $this->instanceTable->findByAnrId($anr->getId()); - $consequences = $this->instanceConsequenceTable->findByAnr($anr); - - // Instances - foreach ($ts as $t) { - foreach ($instances as $instance) { - if ($instance->get($t . 'h')) { - $instance->set($t . 'h', 1); - $instance->set($t, -1); - } else { - $instance->set($t . 'h', 0); - $instance->set($t, $this->approximate( - $instance->get($t), - $scalesData['current'][Scale::TYPE_IMPACT]['min'], - $scalesData['current'][Scale::TYPE_IMPACT]['max'], - $scalesData['external'][Scale::TYPE_IMPACT]['min'], - $scalesData['external'][Scale::TYPE_IMPACT]['max'] - )); - } - - $this->anrInstanceService->refreshImpactsInherited($instance); - } - // Impacts & Consequences. - foreach ($consequences as $conseq) { - $conseq->set($t, $conseq->isHidden() ? -1 : $this->approximate( - $conseq->get($t), - $scalesData['current'][Scale::TYPE_IMPACT]['min'], - $scalesData['current'][Scale::TYPE_IMPACT]['max'], - $scalesData['external'][Scale::TYPE_IMPACT]['min'], - $scalesData['external'][Scale::TYPE_IMPACT]['max'] - )); - $this->instanceConsequenceTable->saveEntity($conseq, false); - } - } - - /* Threats qualification. */ - foreach ($this->threatTable->findByAnr($anr) as $threat) { - $threat->setQualification($this->approximate( - $threat->getQualification(), - $scalesData['current'][Scale::TYPE_THREAT]['min'], - $scalesData['current'][Scale::TYPE_THREAT]['max'], - $scalesData['external'][Scale::TYPE_THREAT]['min'], - $scalesData['external'][Scale::TYPE_THREAT]['max'], - )); - $this->threatTable->saveEntity($threat, false); - } - - // Informational Risks - foreach ($this->instanceRiskTable->findByAnr($anr) as $instanceRisk) { - $instanceRisk->setThreatRate($this->approximate( - $instanceRisk->getThreatRate(), - $scalesData['current'][Scale::TYPE_THREAT]['min'], - $scalesData['current'][Scale::TYPE_THREAT]['max'], - $scalesData['external'][Scale::TYPE_THREAT]['min'], - $scalesData['external'][Scale::TYPE_THREAT]['max'], - )); - $oldVulRate = $instanceRisk->getVulnerabilityRate(); - $instanceRisk->setVulnerabilityRate($this->approximate( - $instanceRisk->getVulnerabilityRate(), - $scalesData['current'][Scale::TYPE_VULNERABILITY]['min'], - $scalesData['current'][Scale::TYPE_VULNERABILITY]['max'], - $scalesData['external'][Scale::TYPE_VULNERABILITY]['min'], - $scalesData['external'][Scale::TYPE_VULNERABILITY]['max'], - )); - $newVulRate = $instanceRisk->getVulnerabilityRate(); - $instanceRisk->setReductionAmount( - $instanceRisk->getReductionAmount() !== 0 - ? $this->approximate($instanceRisk->getReductionAmount(), 0, $oldVulRate, 0, $newVulRate, 0) - : 0 - ); - - $this->anrInstanceRiskService->updateRisks($instanceRisk); - } - - /* Adjust the values of operational risks scales. */ - $this->adjustOperationalRisksScaleValuesBasedOnNewScales($anr, $data); - - $this->updateScalesAndComments($anr, $data); + $withEval = $this->importCacheHelper->getValueFromArrayCache('with_eval'); + /* Import scales. */ + if ($withEval && !empty($data['scales'])) { + /* Adjust the values of information risks' scales. */ + $data['scales'] = $this->adoptOldScalesDataStructureToNewFormat($data, $anr->getLanguage()); + $this->scaleImportProcessor->applyNewScalesFromData($anr, $data['scales']); - $this->updateOperationalRisksScalesAndRelatedInstances($anr, $data); + /* Adjust the values of operational risks' scales. */ + $this->operationalRiskScaleImportProcessor->adjustOperationalRisksScaleValuesBasedOnNewScales($anr, $data); + $this->operationalRiskScaleImportProcessor->updateOperationalRisksScalesAndRelatedInstances($anr, $data); } - $first = true; - $instanceIds = []; - usort($data['instances'], function ($a, $b) { + $instances = []; + $areRecommendationsProcessed = false; + usort($data['instances'], static function ($a, $b) { return $a['instance']['position'] <=> $b['instance']['position']; }); - foreach ($data['instances'] as $inst) { - if ($first) { - if ($data['with_eval'] && isset($data['scales'])) { - $inst['with_eval'] = $data['with_eval']; - $inst['scales'] = $data['scales']; - if (isset($data['operationalRiskScales'])) { - $inst['operationalRiskScales'] = $data['operationalRiskScales']; - } - } - $first = false; - } - $instanceId = $this->importInstanceFromArray($inst, $anr, $parentInstance, $modeImport); - if ($instanceId !== false) { - $instanceIds[] = $instanceId; - } - } - - //Add user consequences to all instances - $instances = $this->instanceTable->findByAnrId($anr->getId()); - $scaleImpactTypes = $this->scaleImpactTypeTable->findByAnr($anr); - foreach ($instances as $instance) { - foreach ($scaleImpactTypes as $siType) { - $instanceConsequence = $this->instanceConsequenceTable->getEntityByFields([ - 'anr' => $anr->getId(), - 'instance' => $instance->getId(), - 'scaleImpactType' => $siType->getId() - ]); - if (empty($instanceConsequence)) { - $consequence = (new InstanceConsequence()) - ->setAnr($anr) - ->setInstance($instance) - ->setObject($instance->getObject()) - ->setScaleImpactType($siType) - ->setCreator($this->connectedUser->getEmail()); - - $this->instanceConsequenceTable->saveEntity($consequence, false); - } - } - } - - $this->instanceConsequenceTable->getDb()->flush(); - - return $instanceIds; - } - - /** - * Method to approximate the value within new bounds, typically when the exported object had a min/max bound - * bigger than the target's ANR bounds. - * - * @param int $value The value to approximate - * @param int $minorig The source min bound - * @param int $maxorig The source max bound - * @param int $mindest The target min bound - * @param int $maxdest The target max bound - * @param int $defaultvalue - * - * @return int The approximated value - */ - private function approximate( - int $value, - int $minorig, - int $maxorig, - int $mindest, - int $maxdest, - int $defaultvalue = -1 - ): int { - if ($value === $maxorig) { - return $maxdest; - } - - if ($value !== -1 && ($maxorig - $minorig) !== -1) { - return (int)min(max( - round(($value / ($maxorig - $minorig + 1)) * ($maxdest - $mindest + 1)), - $mindest - ), $maxdest); - } - - return $defaultvalue; - } - - private function isMonarcVersionLoverThen(string $version): bool - { - return version_compare($this->monarcVersion, $version) < 0; - } - - private function createSetOfRecommendations(array $data, Anr $anr): void - { - if (!empty($data['recSets'])) { - foreach ($data['recSets'] as $recSetUuid => $recommendationSetData) { - if (!isset($this->cachedData['recSets'][$recSetUuid])) { - try { - $recommendationsSet = $this->recommendationSetTable->findByAnrAndUuid($anr, $recSetUuid); - } catch (ORM\EntityNotFoundException $e) { - $recommendationsSet = (new RecommandationSet()) - ->setUuid($recSetUuid) - ->setAnr($anr) - ->setLabel1($recommendationSetData['label1']) - ->setLabel2($recommendationSetData['label2']) - ->setLabel3($recommendationSetData['label3']) - ->setLabel4($recommendationSetData['label4']) - ->setCreator($this->connectedUser->getEmail()); - - $this->recommendationSetTable->saveEntity($recommendationsSet, false); - } - - $this->cachedData['recSets'][$recSetUuid] = $recommendationsSet; - } - } - $this->recommendationSetTable->getDb()->flush(); - } elseif ($this->isMonarcVersionLoverThen('2.8.4')) { - $recommendationsSets = $this->recommendationSetTable->getEntityByFields([ - 'anr' => $anr->getId(), - 'label1' => 'Recommandations importées' - ]); - if (!empty($recommendationsSets)) { - $recommendationSet = current($recommendationsSets); - } else { - $recommendationSet = (new RecommandationSet()) - ->setAnr($anr) - ->setLabel1('Recommandations importées') - ->setLabel2('Imported recommendations') - ->setLabel3('Importierte empfehlungen') - ->setLabel4('Geïmporteerde aanbevelingen') - ->setCreator($this->connectedUser->getEmail()); - - $this->recommendationSetTable->saveEntity($recommendationSet); - } - - $this->cachedData['recSets'][$recommendationSet->getUuid()] = $recommendationSet; - } - - // Create recommendations not linked with recommendation risks. - if (!empty($data['recs'])) { - foreach ($data['recs'] as $recUuid => $recommendationData) { - if (!isset($this->cachedData['recs'][$recUuid])) { - try { - $recommendation = $this->recommendationTable->findByAnrAndUuid($anr, $recUuid); - } catch (ORM\EntityNotFoundException $e) { - $recommendation = (new Recommandation()) - ->setUuid($recommendationData['uuid']) - ->setAnr($anr) - ->setRecommandationSet( - $this->cachedData['recSets'][$recommendationData['recommandationSet']] - ) - ->setComment($recommendationData['comment'] ?? '') - ->setResponsable($recommendationData['responsable'] ?? '') - ->setStatus($recommendationData['status']) - ->setImportance($recommendationData['importance']) - ->setCode($recommendationData['code']) - ->setDescription($recommendationData['description'] ?? '') - ->setCounterTreated($recommendationData['counterTreated']) - ->setCreator($this->connectedUser->getEmail()); - - if (!empty($recommendationData['duedate']['date'])) { - $recommendation->setDueDate(new DateTime($recommendationData['duedate']['date'])); - } - - $this->recommendationTable->saveEntity($recommendation, false); - } - - $this->cachedData['recs'][$recUuid] = $recommendation; - } - } - $this->recommendationTable->getDb()->flush(); - } - } - - private function processRecommendationDataLinkedToRisk( - Anr $anr, - array $recommendationData, - bool $isRiskTreated - ): Recommandation { - if (isset($this->cachedData['recs'][$recommendationData['uuid']])) { - /** @var Recommandation $recommendation */ - $recommendation = $this->cachedData['recs'][$recommendationData['uuid']]; - if ($isRiskTreated && $recommendation->isPositionEmpty()) { - $recommendation->setPosition(++$this->currentAnalyseMaxRecommendationPosition); - $this->recommendationTable->saveEntity($recommendation, false); + foreach ($data['instances'] as $instanceData) { + $instanceData = $this->adaptOldInstanceDataToNewFormat($instanceData, $anr->getLanguage()); + if ($withEval && !empty($instanceData['recs']) && !$areRecommendationsProcessed) { + /* Process all the recommendations' data that are under instance */ + $recommendationSetsData = $this->adaptOldRecommendationSetsDataToNewFormat($data); + $this->recommendationImportProcessor->processRecommendationSetsData($anr, $recommendationSetsData); + $areRecommendationsProcessed = true; } - return $recommendation; - } - - if (isset($this->cachedData['recSets'][$recommendationData['recommandationSet']])) { - $recommendationSet = $this->cachedData['recSets'][$recommendationData['recommandationSet']]; - } else { - $recommendationSet = $this->recommendationSetTable - ->findByAnrAndUuid($anr, $recommendationData['recommandationSet']); - - $this->cachedData['recSets'][$recommendationSet->getUuid()] = $recommendationSet; - } - - $recommendation = $this->recommendationTable->findByAnrCodeAndRecommendationSet( - $anr, - $recommendationData['code'], - $recommendationSet - ); - if ($recommendation === null) { - $recommendation = (new Recommandation())->setUuid($recommendationData['uuid']) - ->setCreator($this->connectedUser->getEmail()); - } else { - $recommendation->setUpdater($this->connectedUser->getEmail()); - } - - $recommendation->setAnr($anr) - ->setRecommandationSet($recommendationSet) - ->setComment($recommendationData['comment'] ?? '') - ->setResponsable($recommendationData['responsable'] ?? '') - ->setStatus($recommendationData['status']) - ->setImportance($recommendationData['importance']) - ->setCode($recommendationData['code']) - ->setDescription($recommendationData['description']) - ->setCounterTreated($recommendationData['counterTreated']); - if (!empty($recommendationData['duedate']['date'])) { - $recommendation->setDueDate(new DateTime($recommendationData['duedate']['date'])); - } - - if ($isRiskTreated && $recommendation->isPositionEmpty()) { - $recommendation->setPosition(++$this->currentAnalyseMaxRecommendationPosition); - } - - $this->recommendationTable->saveEntity($recommendation, false); - - $this->cachedData['recs'][$recommendation->getUuid()] = $recommendation; - - return $recommendation; - } - - /** - * Validates if the data can be imported into the anr. - */ - private function validateIfImportIsPossible(Anr $anr, ?InstanceSuperClass $parent, array $data): void - { - if ($parent !== null - && ( - $parent->getLevel() === InstanceSuperClass::LEVEL_INTER - || $parent->getAnr() !== $anr - ) - ) { - throw new Exception('Parent instance should be in the node tree and the analysis IDs are matched', 412); - } - - if (!empty($data['with_eval']) && empty($data['scales'])) { - throw new Exception('The importing file should include evaluation scales.', 412); - } - } - - private function prepareInstanceConsequences( - array $data, - Anr $anr, - InstanceSuperClass $instance, - MonarcObject $monarcObject, - bool $includeEval - ): void { - $labelKey = 'label' . $anr->getLanguage(); - if (!$includeEval) { - // TODO: improve the method. - $this->anrInstanceService->createInstanceConsequences($instance->getId(), $anr->getId(), $monarcObject); - - return; - } - - $scalesData = $this->getCurrentAndExternalScalesData($anr, $data); - - foreach (Instance::getAvailableScalesCriteria() as $scaleCriteria) { - if ($instance->{'getInherited' . $scaleCriteria}()) { - $instance->{'setInherited' . $scaleCriteria}(1); - $instance->{'set' . $scaleCriteria}(-1); - } else { - $instance->{'setInherited' . $scaleCriteria}(0); - if (!$this->isImportTypeAnr()) { - $instance->{'set' . $scaleCriteria}( - $this->approximate( - $instance->{'get' . $scaleCriteria}(), - $scalesData['external'][Scale::TYPE_IMPACT]['min'], - $scalesData['external'][Scale::TYPE_IMPACT]['max'], - $scalesData['current'][Scale::TYPE_IMPACT]['min'], - $scalesData['current'][Scale::TYPE_IMPACT]['max'] - ) - ); - } - } + $instances[] = $this->instanceImportProcessor + ->processInstanceData($anr, $instanceData, $parentInstance, $modeImport); } - if (!empty($data['consequences'])) { - $localScaleImpact = $this->scaleTable->findByAnrAndType($anr, Scale::TYPE_IMPACT); - $scalesImpactTypes = $this->scaleImpactTypeTable->findByAnr($anr); - $localScalesImpactTypes = []; - foreach ($scalesImpactTypes as $scalesImpactType) { - $localScalesImpactTypes[$scalesImpactType->getLabel($anr->getLanguage())] = $scalesImpactType; - } - $scaleImpactTypeMaxPosition = $this->scaleImpactTypeTable->findMaxPositionByAnrAndScale( - $anr, - $localScaleImpact - ); - - foreach ($data['consequences'] as $consequenceData) { - if (!isset($localScalesImpactTypes[$consequenceData['scaleImpactType'][$labelKey]])) { - $scaleImpactTypeData = $consequenceData['scaleImpactType']; - - $scaleImpactType = (new ScaleImpactType()) - ->setType($scaleImpactTypeData['type']) - ->setLabels($scaleImpactTypeData) - ->setIsSys((bool)$scaleImpactTypeData['isSys']) - ->setIsHidden((bool)$scaleImpactTypeData['isHidden']) - ->setAnr($anr) - ->setScale($localScaleImpact) - ->setPosition(++$scaleImpactTypeMaxPosition) - ->setCreator($this->connectedUser->getEmail()); - - $this->scaleImpactTypeTable->saveEntity($scaleImpactType, false); - - $localScalesImpactTypes[$consequenceData['scaleImpactType'][$labelKey]] = $scaleImpactType; - } - - $instanceConsequence = (new InstanceConsequence()) - ->setAnr($anr) - ->setObject($monarcObject) - ->setInstance($instance) - ->setScaleImpactType($localScalesImpactTypes[$consequenceData['scaleImpactType'][$labelKey]]) - ->setIsHidden((bool)$consequenceData['isHidden']) - ->setLocallyTouched($consequenceData['locallyTouched']) - ->setCreator($this->connectedUser->getEmail()); - - foreach (InstanceConsequence::getAvailableScalesCriteria() as $scaleCriteriaKey => $scaleCriteria) { - if ($instanceConsequence->isHidden()) { - $value = -1; - } else { - $value = $this->isImportTypeAnr() - ? $consequenceData[$scaleCriteriaKey] - : $this->approximate( - $consequenceData[$scaleCriteriaKey], - $scalesData['external'][Scale::TYPE_IMPACT]['min'], - $scalesData['external'][Scale::TYPE_IMPACT]['max'], - $scalesData['current'][Scale::TYPE_IMPACT]['min'], - $scalesData['current'][Scale::TYPE_IMPACT]['max'] - ); - } - $instanceConsequence->{'set' . $scaleCriteria}($value); - } - - $this->instanceConsequenceTable->saveEntity($instanceConsequence, false); - } - - $this->instanceConsequenceTable->getDb()->flush(); - } - } - - /** - * The prepared cachedData['scales'] are used to convert(approximate) the risks' values of importing instance(s), - * from external to current scales (in case of instance(s) import). - * For ANR import, the current analysis risks' values are converted from current to external scales. - */ - private function getCurrentAndExternalScalesData(Anr $anr, array $data): array - { - if (empty($this->cachedData['scales'])) { - $scales = $this->scaleTable->findByAnr($anr); - $this->cachedData['scales']['current'] = []; - $this->cachedData['scales']['external'] = $data['scales']; - - foreach ($scales as $scale) { - $this->cachedData['scales']['current'][$scale->getType()] = [ - 'min' => $scale->getMin(), - 'max' => $scale->getMax(), - ]; - } - } - - return $this->cachedData['scales']; - } - - private function processInstanceRisks( - array $data, - Anr $anr, - InstanceSuperClass $instance, - MonarcObject $monarcObject, - bool $includeEval, - string $modeImport - ): void { - if (empty($data['risks'])) { - return; - } - - $scalesData = []; - if ($includeEval && !$this->isImportTypeAnr()) { - $scalesData = $this->getCurrentAndExternalScalesData($anr, $data); - } - - foreach ($data['risks'] as $instanceRiskData) { - $threatData = $data['threats'][$instanceRiskData['threat']]; - $vulnerabilityData = $data['vuls'][$instanceRiskData['vulnerability']]; - - $instanceRisk = $this->instanceRiskTable->findByInstanceAssetThreatUuidAndVulnerabilityUuid( - $instance, - $monarcObject->getAsset(), - $threatData['uuid'], - $vulnerabilityData['uuid'] - ); - - if ((int)$instanceRiskData['specific'] === InstanceRisk::TYPE_SPECIFIC) { - $threat = $this->importCacheHelper->getItemFromArrayCache('threats', $threatData['uuid']) - ?: $this->threatTable->findByAnrAndUuid($anr, $threatData['uuid']); - if ($threat === null) { - /* The code should be unique. */ - $threatData['code'] = - $this->importCacheHelper->getItemFromArrayCache('threats_codes', $threatData['code']) !== null - || $this->threatTable->existsWithAnrAndCode($anr, $threatData['code']) - ? $threatData['code'] . '-' . time() - : $threatData['code']; - - $threat = (new Threat()) - ->setUuid($threatData['uuid']) - ->setAnr($anr) - ->setCode($threatData['code']) - ->setLabels($threatData) - ->setDescriptions($threatData) - ->setMode((int)$threatData['mode']) - ->setStatus((int)$threatData['status']) - ->setTrend((int)$threatData['trend']) - ->setQualification((int)$threatData['qualification']) - ->setComment($threatData['comment'] ?? '') - ->setCreator($this->connectedUser->getEmail()); - if (isset($threatData['c'])) { - $threat->setConfidentiality((int)$threatData['c']); - } - if (isset($threatData['i'])) { - $threat->setIntegrity((int)$threatData['i']); - } - if (isset($threatData['a'])) { - $threat->setAvailability((int)$threatData['a']); - } - - /* - * Unfortunately we don't add "themes" on the same level as "risks" and "threats", - * but only under "asset". - * TODO: we should add theme linked to the threat inside of the threat object - * data when export later on. after we can set it $threat->setTheme($theme); - */ - - $this->threatTable->saveEntity($threat, false); - - $this->importCacheHelper->addItemToArrayCache('threats', $threat, $threat->getUuid()); - $this->importCacheHelper - ->addItemToArrayCache('threats_codes', $threat->getCode(), $threat->getCode()); - } - - $vulnerability = $this->importCacheHelper - ->getItemFromArrayCache('vulnerabilities', $vulnerabilityData['uuid']) - ?: $this->vulnerabilityTable->findByAnrAndUuid($anr, $vulnerabilityData['uuid'], false); - if ($vulnerability === null) { - /* The code should be unique. */ - $vulnerabilityData['code'] = - $this->importCacheHelper - ->getItemFromArrayCache('vulnerabilities_codes', $vulnerabilityData['code']) !== null - || $this->vulnerabilityTable->existsWithAnrAndCode($anr, $vulnerabilityData['code']) - ? $vulnerabilityData['code'] . '-' . time() - : $vulnerabilityData['code']; - - $vulnerability = (new Vulnerability()) - ->setUuid($vulnerabilityData['uuid']) - ->setAnr($anr) - ->setLabels($vulnerabilityData) - ->setDescriptions($vulnerabilityData) - ->setCode($vulnerabilityData['code']) - ->setMode($vulnerabilityData['mode']) - ->setStatus($vulnerabilityData['status']) - ->setCreator($this->connectedUser->getEmail()); - - $this->vulnerabilityTable->saveEntity($vulnerability, false); - - $this->importCacheHelper - ->addItemToArrayCache('vulnerabilities', $vulnerability, $vulnerability->getUuid()); - $this->importCacheHelper->addItemToArrayCache( - 'vulnerabilities_codes', - $vulnerability->getCode(), - $vulnerability->getCode() - ); - } - - $instanceRisk = $this->createInstanceRiskFromData( - $instanceRiskData, - $anr, - $instance, - $monarcObject->getAsset(), - $threat, - $vulnerability - ); - - $this->instanceRiskTable->saveEntity($instanceRisk, false); - - /* - * Create specific risks linked to the brother instances. - */ - $instanceBrothers = $this->getInstanceBrothers($instance); - foreach ($instanceBrothers as $instanceBrother) { - $instanceRiskBrother = $this->createInstanceRiskFromData( - $instanceRiskData, - $anr, - $instanceBrother, - $monarcObject->getAsset(), - $threat, - $vulnerability - ); - - $this->instanceRiskTable->saveEntity($instanceRiskBrother, false); - } - } - - if ($instanceRisk !== null && $includeEval) { - $instanceRisk->setThreatRate( - $this->isImportTypeAnr() - ? $instanceRiskData['threatRate'] - : $this->approximate( - $instanceRiskData['threatRate'], - $scalesData['external'][Scale::TYPE_THREAT]['min'], - $scalesData['external'][Scale::TYPE_THREAT]['max'], - $scalesData['current'][Scale::TYPE_THREAT]['min'], - $scalesData['current'][Scale::TYPE_THREAT]['max'] - ) - ); - $instanceRisk->setVulnerabilityRate( - $this->isImportTypeAnr() - ? $instanceRiskData['vulnerabilityRate'] - : $this->approximate( - $instanceRiskData['vulnerabilityRate'], - $scalesData['external'][Scale::TYPE_VULNERABILITY]['min'], - $scalesData['external'][Scale::TYPE_VULNERABILITY]['max'], - $scalesData['current'][Scale::TYPE_VULNERABILITY]['min'], - $scalesData['current'][Scale::TYPE_VULNERABILITY]['max'] - ) - ); - $instanceRisk->setMh($instanceRiskData['mh']); - $instanceRisk->setKindOfMeasure($instanceRiskData['kindOfMeasure']); - $instanceRisk->setComment($instanceRiskData['comment'] ?? ''); - $instanceRisk->setCommentAfter($instanceRiskData['commentAfter'] ?? ''); - - // La valeur -1 pour le reduction_amount n'a pas de sens, c'est 0 le minimum. Le -1 fausse - // les calculs. - // Cas particulier, faudrait pas mettre n'importe quoi dans cette colonne si on part d'une scale - // 1 - 7 vers 1 - 3 on peut pas avoir une réduction de 4, 5, 6 ou 7 - $instanceRisk->setReductionAmount( - $instanceRiskData['reductionAmount'] !== -1 - ? $this->approximate( - $instanceRiskData['reductionAmount'], - 0, - $instanceRiskData['vulnerabilityRate'], - 0, - $instanceRisk->getVulnerabilityRate(), - 0 - ) - : 0 - ); - $this->instanceRiskTable->saveEntity($instanceRisk, false); - - // Merge all fields for global assets. - if ($modeImport === 'merge' - && !$instanceRisk->isSpecific() - && $instance->getObject()->isScopeGlobal() - ) { - $objectIdsBrothers = $this->instanceTable->findByAnrAndObject($anr, $instance->getObject()); - - // TODO: findBy... - /** @var InstanceRisk $instanceRiskBrothers */ - $instanceRiskBrothers = current($this->instanceRiskTable->getEntityByFields([ - 'anr' => $anr->getId(), - 'instance' => ['op' => 'IN', 'value' => $objectIdsBrothers], - 'amv' => [ - 'anr' => $anr->getId(), - 'uuid' => $instanceRisk->getAmv()->getUuid(), - ] - ])); - - if ($instanceRiskBrothers !== null) { - $dataUpdate = []; - $dataUpdate['anr'] = $anr->getId(); - $dataUpdate['threatRate'] = $instanceRiskBrothers->getThreatRate(); - $dataUpdate['vulnerabilityRate'] = $instanceRiskBrothers->getVulnerabilityRate(); - $dataUpdate['kindOfMeasure'] = $instanceRiskBrothers->getKindOfMeasure(); - $dataUpdate['reductionAmount'] = $instanceRiskBrothers->getReductionAmount(); - // Check if comment is different. - if (strcmp($instanceRiskBrothers->getComment(), $instanceRisk->getComment()) !== 0 - && strpos($instanceRiskBrothers->getComment(), $instanceRisk->getComment()) === false - ) { - $dataUpdate['comment'] = // Merge comments - $instanceRiskBrothers->getComment() . "\n\n" . $instanceRisk->getComment(); - } else { - $dataUpdate['comment'] = $instanceRiskBrothers->getComment(); - } - - $this->anrInstanceRiskService->update($instanceRisk->getId(), $dataUpdate); - } - } - - // Process recommendations. - if (!empty($data['recos'][$instanceRiskData['id']])) { - foreach ($data['recos'][$instanceRiskData['id']] as $reco) { - $recommendation = $this->processRecommendationDataLinkedToRisk( - $anr, - $reco, - $instanceRiskData['kindOfMeasure'] !== InstanceRiskSuperClass::KIND_NOT_TREATED - ); - $recommendationRisk = (new RecommandationRisk()) - ->setAnr($anr) - ->setInstance($instance) - ->setInstanceRisk($instanceRisk) - ->setGlobalObject($monarcObject->isScopeGlobal() ? $monarcObject : null) - ->setAsset($instanceRisk->getAsset()) - ->setThreat($instanceRisk->getThreat()) - ->setVulnerability($instanceRisk->getVulnerability()) - ->setCommentAfter((string)$reco['commentAfter']) - ->setRecommandation($recommendation) - ->setCreator($this->connectedUser->getEmail()); - - $this->recommendationRiskTable->saveEntity($recommendationRisk, false); - - // Replicate recommendation to brothers. - if ($modeImport === 'merge' && $recommendationRisk->hasGlobalObjectRelation()) { - $brotherInstances = $this->getInstanceBrothers($instance); - if (!empty($brotherInstances)) { - foreach ($brotherInstances as $brotherInstance) { - // Get the risks of brothers - /** @var InstanceRisk[] $brothers */ - if ($instanceRisk->isSpecific()) { - $brothers = $this->instanceRiskTable->findByInstanceAndInstanceRiskRelations( - $brotherInstance, - $instanceRisk, - true - ); - } else { - $brothers = $this->instanceRiskTable->findByInstanceAndAmv( - $brotherInstance, - $instanceRisk->getAmv() - ); - } - - foreach ($brothers as $brother) { - $recommendationRiskBrother = $this->recommendationRiskTable - ->findByInstanceRiskAndRecommendation($brother, $recommendation); - if ($recommendationRiskBrother === null) { - $recommendationRiskBrother = (new RecommandationRisk()) - ->setAnr($anr) - ->setInstance($brotherInstance) - ->setInstanceRisk($brother) - ->setGlobalObject( - $monarcObject->isScopeGlobal() ? $monarcObject : null - ) - ->setAsset($instanceRisk->getAsset()) - ->setThreat($instanceRisk->getThreat()) - ->setVulnerability($instanceRisk->getVulnerability()) - ->setCommentAfter((string)$reco['commentAfter']) - ->setRecommandation($recommendation) - ->setCreator($this->connectedUser->getEmail()); - - $this->recommendationRiskTable - ->saveEntity($recommendationRiskBrother, false); - } - } - } - $this->recommendationRiskTable->getDb()->flush(); - } - } - } - $this->recommendationRiskTable->getDb()->flush(); - } - } - - // Check recommendations from a brother - $instanceBrothers = $this->getInstanceBrothers($instance); - if (!empty($instanceBrothers) && $instanceRisk !== null && !$instanceRisk->isSpecific()) { - $instanceRiskBrothers = $this->instanceRiskTable->findByInstanceAndAmv( - current($instanceBrothers), - $instanceRisk->getAmv() - ); - - foreach ($instanceRiskBrothers as $instanceRiskBrother) { - /** @var RecommandationRisk[] $brotherRecoRisks */ - // Get recommendation of brother - $brotherRecoRisks = $this->recommendationRiskTable->getEntityByFields([ - 'anr' => $anr->getId(), - 'instanceRisk' => $instanceRiskBrother->getId(), - 'instance' => ['op' => '!=', 'value' => $instance->getId()], - 'globalObject' => [ - 'anr' => $anr->getId(), - 'uuid' => $monarcObject->getUuid(), - ] - ]); - - if (!empty($brotherRecoRisks)) { - foreach ($brotherRecoRisks as $brotherRecoRisk) { - $recommendationRisk = $this->recommendationRiskTable->findByInstanceRiskAndRecommendation( - $instanceRisk, - $brotherRecoRisk->getRecommandation() - ); - - if ($recommendationRisk === null) { - $recommendationRisk = (new RecommandationRisk()) - ->setAnr($anr) - ->setInstance($instance) - ->setInstanceRisk($brotherRecoRisk->getInstanceRisk()) - ->setGlobalObject($brotherRecoRisk->getGlobalObject()) - ->setAsset($brotherRecoRisk->getAsset()) - ->setThreat($brotherRecoRisk->getThreat()) - ->setVulnerability($brotherRecoRisk->getVulnerability()) - ->setCommentAfter($brotherRecoRisk->getCommentAfter()) - ->setRecommandation($brotherRecoRisk->getRecommandation()) - ->setCreator($this->connectedUser->getEmail()); - - $this->recommendationRiskTable->saveEntity($recommendationRisk, false); - } - } - - $this->recommendationRiskTable->getDb()->flush(); - } - } - } - } - - // Check recommandations from specific risk of brothers - $recoToCreate = []; - // Get all specific risks of instance - $specificRisks = $this->instanceRiskTable->findByInstance($instance, true); - foreach ($specificRisks as $specificRisk) { - // TODO: replace all the queries with QueryBuilder. Review the logic. - // Get recommandations of brothers - /** @var RecommandationRisk[] $exitingRecoRisks */ - $exitingRecoRisks = $this->recommendationRiskTable->getEntityByFields([ - 'anr' => $anr->getId(), - 'asset' => ['anr' => $anr->getId(), 'uuid' => $specificRisk->getAsset()->getUuid()], - 'threat' => ['anr' => $anr->getId(), 'uuid' => $specificRisk->getThreat()->getUuid()], - 'vulnerability' => ['anr' => $anr->getId(), 'uuid' => $specificRisk->getVulnerability()->getUuid()], - ]); - foreach ($exitingRecoRisks as $exitingRecoRisk) { - if ($instance->getId() !== $exitingRecoRisk->getInstance()->getId()) { - $recoToCreate[] = $exitingRecoRisk; - } - } - } - - /** @var RecommandationRisk $recommendationRiskToCreate */ - foreach ($recoToCreate as $recommendationRiskToCreate) { - // Check if reco-risk link exist - $recoCreated = $this->recommendationRiskTable->getEntityByFields([ - 'recommandation' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getRecommandation()->getUuid(), - ], - 'instance' => $instance->getId(), - 'asset' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getAsset()->getUuid(), - ], - 'threat' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getThreat()->getUuid(), - ], - 'vulnerability' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getVulnerability()->getUuid(), - ] - ]); - - if (empty($recoCreated)) { - // TODO: check if we can get it in different way as it is too heavy. - $instanceRiskSpecific = current($this->instanceRiskTable->getEntityByFields([ - 'anr' => $anr->getId(), - 'instance' => $instance->getId(), - 'specific' => 1, - 'asset' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getAsset()->getUuid(), - ], - 'threat' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getThreat()->getUuid(), - ], - 'vulnerability' => [ - 'anr' => $anr->getId(), - 'uuid' => $recommendationRiskToCreate->getVulnerability()->getUuid(), - ], - ])); - - $recommendationRisk = (new RecommandationRisk()) - ->setAnr($anr) - ->setInstance($instance) - ->setInstanceRisk($instanceRiskSpecific) - ->setGlobalObject($recommendationRiskToCreate->getGlobalObject()) - ->setAsset($instanceRiskSpecific->getAsset()) - ->setThreat($instanceRiskSpecific->getThreat()) - ->setVulnerability($instanceRiskSpecific->getVulnerability()) - ->setCommentAfter($recommendationRiskToCreate->getCommentAfter()) - ->setRecommandation($recommendationRiskToCreate->getRecommandation()) - ->setCreator($this->connectedUser->getEmail()); - - $this->recommendationRiskTable->saveEntity($recommendationRisk, false); - } - } - $this->recommendationRiskTable->getDb()->flush(); - - // on met finalement à jour les risques en cascade - $this->anrInstanceService->updateRisks($instance); - } - - private function processOperationalInstanceRisks( - array $data, - Anr $anr, - Instance $instance, - MonarcObject $monarcObject, - bool $includeEval - ): void { - if (empty($data['risksop'])) { - return; - } - - $operationalRiskScalesData = $this->getCurrentOperationalRiskScalesData($anr); - $externalOperationalRiskScalesData = []; - $areScalesLevelsOfLikelihoodDifferent = false; - $areImpactScaleTypesValuesDifferent = false; - $matchedScaleTypesMap = []; - if ($includeEval && !$this->isImportTypeAnr()) { - $externalOperationalRiskScalesData = $this->getExternalOperationalRiskScalesData($anr, $data); - $areScalesLevelsOfLikelihoodDifferent = $this->areScalesLevelsOfTypeDifferent( - OperationalRiskScale::TYPE_LIKELIHOOD, - $operationalRiskScalesData, - $externalOperationalRiskScalesData - ); - $areImpactScaleTypesValuesDifferent = $this->areScaleTypeValuesDifferent( - OperationalRiskScale::TYPE_IMPACT, - $operationalRiskScalesData, - $externalOperationalRiskScalesData - ); - $matchedScaleTypesMap = $this->matchAndGetOperationalRiskScaleTypesMap( - $anr, - $operationalRiskScalesData, - $externalOperationalRiskScalesData - ); - } - $oldInstanceRiskFieldsMapToScaleTypesFields = [ - ['brutR' => 'BrutValue', 'netR' => 'NetValue', 'targetedR' => 'TargetedValue'], - ['brutO' => 'BrutValue', 'netO' => 'NetValue', 'targetedO' => 'TargetedValue'], - ['brutL' => 'BrutValue', 'netL' => 'NetValue', 'targetedL' => 'TargetedValue'], - ['brutF' => 'BrutValue', 'netF' => 'NetValue', 'targetedF' => 'TargetedValue'], - ['brutP' => 'BrutValue', 'netP' => 'NetValue', 'targetedP' => 'TargetedValue'], - ]; - - foreach ($data['risksop'] as $operationalRiskData) { - $operationalInstanceRisk = (new InstanceRiskOp()) - ->setAnr($anr) - ->setInstance($instance) - ->setObject($monarcObject) - ->setRiskCacheLabels([ - 'riskCacheLabel1' => $operationalRiskData['riskCacheLabel1'], - 'riskCacheLabel2' => $operationalRiskData['riskCacheLabel2'], - 'riskCacheLabel3' => $operationalRiskData['riskCacheLabel3'], - 'riskCacheLabel4' => $operationalRiskData['riskCacheLabel4'], - ]) - ->setRiskCacheDescriptions([ - 'riskCacheDescription1' => $operationalRiskData['riskCacheDescription1'], - 'riskCacheDescription2' => $operationalRiskData['riskCacheDescription2'], - 'riskCacheDescription3' => $operationalRiskData['riskCacheDescription3'], - 'riskCacheDescription4' => $operationalRiskData['riskCacheDescription4'], - ]) - ->setBrutProb((int)$operationalRiskData['brutProb']) - ->setNetProb((int)$operationalRiskData['netProb']) - ->setTargetedProb((int)$operationalRiskData['targetedProb']) - ->setCacheBrutRisk((int)$operationalRiskData['cacheBrutRisk']) - ->setCacheNetRisk((int)$operationalRiskData['cacheNetRisk']) - ->setCacheTargetedRisk((int)$operationalRiskData['cacheTargetedRisk']) - ->setKindOfMeasure((int)$operationalRiskData['kindOfMeasure']) - ->setComment($operationalRiskData['comment'] ?? '') - ->setMitigation($operationalRiskData['mitigation'] ?? '') - ->setSpecific((int)$operationalRiskData['specific']) - ->setContext($operationalRiskData['context'] ?? '') - ->setCreator($this->connectedUser->getEmail()); - - if (!empty($operationalRiskData['riskOwner'])) { - $instanceRiskOwner = $this->anrInstanceRiskService->getOrCreateInstanceRiskOwner( - $anr, - $operationalRiskData['riskOwner'] - ); - $operationalInstanceRisk->setInstanceRiskOwner($instanceRiskOwner); - } - - if ($areScalesLevelsOfLikelihoodDifferent) { - $this->adjustOperationalRisksProbabilityScales( - $operationalInstanceRisk, - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_LIKELIHOOD], - $operationalRiskScalesData[OperationalRiskScale::TYPE_LIKELIHOOD] - ); - } - - if (!empty($operationalRiskData['rolfRisk']) && $monarcObject->getRolfTag() !== null) { - /** @var RolfRisk|null $rolfRisk */ - $rolfRisk = $this->importCacheHelper - ->getItemFromArrayCache('rolf_risks_by_old_ids', (int)$operationalRiskData['rolfRisk']); - if ($rolfRisk !== null) { - $operationalInstanceRisk - ->setRolfRisk($rolfRisk) - ->setRiskCacheCode($rolfRisk->getCode()); - } - } - - $impactScale = $operationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT]; - foreach ($impactScale['operationalRiskScaleTypes'] as $index => $scaleType) { - /** @var OperationalRiskScaleType $operationalRiskScaleType */ - $operationalRiskScaleType = $scaleType['object']; - $operationalInstanceRiskScale = (new OperationalInstanceRiskScale()) - ->setAnr($anr) - ->setOperationalRiskScaleType($operationalRiskScaleType) - ->setOperationalInstanceRisk($operationalInstanceRisk) - ->setCreator($this->connectedUser->getEmail()); - - if ($includeEval) { - /* The format is since v2.11.0 */ - if (isset($operationalRiskData['scalesValues'])) { - $externalScaleTypeId = null; - if ($this->isImportTypeAnr()) { - /* For anr import, match current scale type translation key with external ids. */ - $externalScaleTypeId = $this->getExternalScaleTypeIdByCurrentScaleLabelTranslationKey( - $operationalRiskScaleType->getLabelTranslationKey() - ); - } elseif (isset($matchedScaleTypesMap['currentScaleTypeKeysToExternalIds'] - [$operationalRiskScaleType->getLabelTranslationKey()]) - ) { - /* For instance import, match current scale type translation key with external ids. */ - $externalScaleTypeId = $matchedScaleTypesMap['currentScaleTypeKeysToExternalIds'] - [$operationalRiskScaleType->getLabelTranslationKey()]; - } - if ($externalScaleTypeId !== null - && isset($operationalRiskData['scalesValues'][$externalScaleTypeId]) - ) { - $scalesValueData = $operationalRiskData['scalesValues'][$externalScaleTypeId]; - $operationalInstanceRiskScale->setBrutValue($scalesValueData['brutValue']); - $operationalInstanceRiskScale->setNetValue($scalesValueData['netValue']); - $operationalInstanceRiskScale->setTargetedValue($scalesValueData['targetedValue']); - if ($areImpactScaleTypesValuesDifferent) { - /* We convert from the importing new scales to the current anr scales. */ - $this->adjustOperationalInstanceRisksScales( - $operationalInstanceRiskScale, - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT], - $impactScale - ); - } - } - /* The format before v2.11.0. Update only first 5 scales (ROLFP if not changed by user). */ - } elseif ($index < 5) { - foreach ($oldInstanceRiskFieldsMapToScaleTypesFields[$index] as $oldFiled => $typeField) { - $operationalInstanceRiskScale->{'set' . $typeField}($operationalRiskData[$oldFiled]); - } - if ($areImpactScaleTypesValuesDifferent) { - /* We convert from the importing new scales to the current anr scales. */ - $this->adjustOperationalInstanceRisksScales( - $operationalInstanceRiskScale, - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT], - $impactScale - ); - } - } - } - - $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); - } - - if (!empty($matchedScaleTypesMap['notMatchedScaleTypes']) && !$this->isImportTypeAnr()) { - /* In case of instance import, there is a need to create external scale types in case if - the linked values are set for at least one operational instance risk. - The new created type has to be linked with all the existed risks. */ - $anrLanguageCode = $this->getAnrLanguageCode($anr); - foreach ($matchedScaleTypesMap['notMatchedScaleTypes'] as $extScaleTypeId => $extScaleTypeData) { - if (isset($operationalRiskData['scalesValues'][$extScaleTypeId])) { - $scalesValueData = $operationalRiskData['scalesValues'][$extScaleTypeId]; - if ($scalesValueData['netValue'] !== -1 - || $scalesValueData['brutValue'] !== -1 - || $scalesValueData['targetedValue'] !== -1 - ) { - $labelTranslationKey = (string)Uuid::uuid4(); - $operationalRiskScaleType = (new OperationalRiskScaleType()) - ->setAnr($anr) - ->setOperationalRiskScale($impactScale['object']) - ->setLabelTranslationKey($labelTranslationKey) - ->setCreator($this->connectedUser->getEmail()); - $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType, false); - - $translation = (new Translation()) - ->setAnr($anr) - ->setType(Translation::OPERATIONAL_RISK_SCALE_TYPE) - ->setKey($labelTranslationKey) - ->setValue($extScaleTypeData['translation']['value']) - ->setLang($anrLanguageCode) - ->setCreator($this->connectedUser->getEmail()); - $this->translationTable->save($translation, false); - - foreach ($extScaleTypeData['operationalRiskScaleComments'] as $scaleCommentData) { - $this->createOrUpdateOperationalRiskScaleComment( - $anr, - false, - $impactScale['object'], - $scaleCommentData, - [], - [], - $operationalRiskScaleType - ); - } - - $operationalInstanceRiskScale = (new OperationalInstanceRiskScale()) - ->setAnr($anr) - ->setOperationalInstanceRisk($operationalInstanceRisk) - ->setOperationalRiskScaleType($operationalRiskScaleType) - ->setBrutValue($scalesValueData['brutValue']) - ->setNetValue($scalesValueData['netValue']) - ->setTargetedValue($scalesValueData['targetedValue']) - ->setCreator($this->connectedUser->getEmail()); - $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale); - - $this->adjustOperationalInstanceRisksScales( - $operationalInstanceRiskScale, - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT], - $impactScale - ); - - /* To swap the scale risk between the to keys in the map as it is already matched. */ - unset($matchedScaleTypesMap['notMatchedScaleTypes'][$extScaleTypeId]); - $matchedScaleTypesMap['currentScaleTypeKeysToExternalIds'] - [$operationalRiskScaleType->getLabelTranslationKey()] = $extScaleTypeId; - - /* Due to the new scale type and related comments the cache has to be reset. */ - $this->cachedData['currentOperationalRiskScalesData'] = []; - $operationalRiskScalesData = $this->getCurrentOperationalRiskScalesData($anr); - $areImpactScaleTypesValuesDifferent = true; - - /* Link the newly created scale type to all the existed operational risks. */ - $operationalInstanceRisks = $this->instanceRiskOpTable->findByAnrAndInstance( - $anr, - $instance - ); - foreach ($operationalInstanceRisks as $operationalInstanceRiskToUpdate) { - if ($operationalInstanceRiskToUpdate->getId() !== $operationalInstanceRisk->getId()) { - $operationalInstanceRiskScale = (new OperationalInstanceRiskScale()) - ->setAnr($anr) - ->setOperationalInstanceRisk($operationalInstanceRiskToUpdate) - ->setOperationalRiskScaleType($operationalRiskScaleType) - ->setCreator($this->connectedUser->getEmail()); - $this->operationalInstanceRiskScaleTable->save( - $operationalInstanceRiskScale, - false - ); - } - } - } - } - } - } - - if ($includeEval) { - /* recalculate the cached risk values */ - $this->anrInstanceRiskOpService->updateRiskCacheValues($operationalInstanceRisk, false); - } - - $this->instanceRiskOpTable->saveEntity($operationalInstanceRisk, false); - - /* Process recommendations related to the operational risk. */ - if ($includeEval && !empty($data['recosop'][$operationalRiskData['id']])) { - foreach ($data['recosop'][$operationalRiskData['id']] as $recommendationData) { - $recommendation = $this->processRecommendationDataLinkedToRisk( - $anr, - $recommendationData, - $operationalRiskData['kindOfMeasure'] !== InstanceRiskOpSuperClass::KIND_NOT_TREATED - ); - - $recommendationRisk = (new RecommandationRisk()) - ->setInstance($instance) - ->setInstanceRiskOp($operationalInstanceRisk) - ->setGlobalObject($monarcObject->isScopeGlobal() ? $monarcObject : null) - ->setCommentAfter($recommendationData['commentAfter'] ?? '') - ->setRecommandation($recommendation); - - // TODO: remove the trick when #240 is done. - $this->recommendationRiskTable->saveEntity($recommendationRisk); - $this->recommendationRiskTable->saveEntity($recommendationRisk->setAnr($anr), false); - } - } - - $this->recommendationRiskTable->getDb()->flush(); - } - } - - private function matchAndGetOperationalRiskScaleTypesMap( - Anr $anr, - array $operationalRiskScalesData, - array $externalOperationalRiskScalesData - ): array { - $matchedScaleTypesMap = [ - 'currentScaleTypeKeysToExternalIds' => [], - 'notMatchedScaleTypes' => [], - ]; - $anrLanguageCode = $this->getAnrLanguageCode($anr); - $scaleTypesTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::OPERATIONAL_RISK_SCALE_TYPE], - $anrLanguageCode - ); - $scaleTypesData = $operationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT] - ['operationalRiskScaleTypes']; - $externalScaleTypesData = - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT]['operationalRiskScaleTypes']; - foreach ($externalScaleTypesData as $externalScaleTypeData) { - $isMatched = false; - foreach ($scaleTypesData as $scaleTypeData) { - /** @var OperationalRiskScaleType $scaleType */ - $scaleType = $scaleTypeData['object']; - $scaleTypeTranslation = $scaleTypesTranslations[$scaleType->getLabelTranslationKey()]; - if ($externalScaleTypeData['translation']['value'] === $scaleTypeTranslation->getValue()) { - $matchedScaleTypesMap['currentScaleTypeKeysToExternalIds'][$scaleType->getLabelTranslationKey()] - = $externalScaleTypeData['id']; - $isMatched = true; - break; - } - } - if (!$isMatched) { - $matchedScaleTypesMap['notMatchedScaleTypes'][$externalScaleTypeData['id']] = $externalScaleTypeData; - } - } - - return $matchedScaleTypesMap; - } - - private function getExternalScaleTypeIdByCurrentScaleLabelTranslationKey(string $labelTranslationKey): ?int - { - return $this->cachedData['operationalRiskScaleTypes']['currentScaleTypeLabelTranslationKeyToExternalIds'] - [$labelTranslationKey] ?? null; - } - - private function areScalesLevelsOfTypeDifferent( - int $type, - array $operationalRiskScales, - array $externalOperationalRiskScalesData - ): bool { - foreach ($operationalRiskScales as $scaleType => $operationalRiskScale) { - if ($scaleType === $type) { - $externalScaleDataOfType = $externalOperationalRiskScalesData[$type]; - if ($operationalRiskScale['min'] !== $externalScaleDataOfType['min'] - || $operationalRiskScale['max'] !== $externalScaleDataOfType['max']) { - return true; - } - } - } - - return false; - } - - /** - * Checks if any of the scale comments values related to the scale types have different scaleValue - * then in the new operational scale data. - */ - public function areScaleTypeValuesDifferent( - int $type, - array $operationalRiskScales, - array $extOperationalRiskScalesData - ): bool { - foreach ($operationalRiskScales[$type]['commentsIndexToValueMap'] as $scaleIndex => $scaleValue) { - if (!isset($extOperationalRiskScalesData[$type]['commentsIndexToValueMap'][$scaleIndex])) { - return true; - } - $extScaleValue = $extOperationalRiskScalesData[$type]['commentsIndexToValueMap'][$scaleIndex]; - if ($scaleValue !== $extScaleValue) { - return true; - } - } - - return false; - } - - /** - * Update the instance impacts from brothers for global assets. - * - * @param InstanceSuperClass $instance - * @param string $modeImport - */ - private function updateInstanceImpactsFromBrothers(InstanceSuperClass $instance, string $modeImport): void - { - if ($modeImport === 'merge' && $instance->getObject()->isScopeGlobal()) { - $instanceBrothers = $this->getInstanceBrothers($instance); - if (!empty($instanceBrothers)) { - // Update impacts of the instance. We use only one brother global instance as the impacts are the same. - $instanceBrother = current($instanceBrothers); - foreach (InstanceConsequence::getAvailableScalesCriteria() as $scaleCriteria) { - if ($instanceBrother->{'getInherited' . $scaleCriteria}() === 0) { - $instance->{'setInherited' . $scaleCriteria}(0); - $instance->{'set' . $scaleCriteria}($instanceBrother->{'get' . $scaleCriteria}()); - } elseif ($instance->getParent()) { - $instance->{'setInherited' . $scaleCriteria}(1); - $instance->{'set' . $scaleCriteria}($instance->getParent()->{'get' . $scaleCriteria}()); - } else { - $instance->{'setInherited' . $scaleCriteria}(1); - $instance->{'set' . $scaleCriteria}($instanceBrother->{'get' . $scaleCriteria}()); - } - } - - // Update consequences for all brothers. - foreach ($instanceBrothers as $instanceBrother) { - foreach ($instanceBrother->getInstanceConsequences() as $instanceConsequence) { - $instanceConsequenceBrothers = $this->instanceConsequenceTable - ->findByAnrInstanceAndScaleImpactType( - $instance->getAnr(), - $instance, - $instanceConsequence->getScaleImpactType() - ); - foreach ($instanceConsequenceBrothers as $instanceConsequenceBrother) { - $instanceConsequenceBrother->setIsHidden($instanceConsequence->isHidden()) - ->setLocallyTouched($instanceConsequence->getLocallyTouched()) - ->setConfidentiality($instanceConsequence->getConfidentiality()) - ->setIntegrity($instanceConsequence->getIntegrity()) - ->setAvailability($instanceConsequence->getAvailability()); - - $this->instanceConsequenceTable->saveEntity($instanceConsequenceBrother, false); - } - } - } - - $this->instanceTable->saveEntity($instance); - } - } - } - - /** - * @return Instance[] - */ - private function getInstanceBrothers(InstanceSuperClass $instance): array - { - if (!isset($this->cachedData['instanceBrothers'][$instance->getId()])) { - $this->cachedData['instanceBrothers'][$instance->getId()] = $this->instanceTable - ->findByAnrAssetAndObjectExcludeInstance( - $instance->getAnr(), - $instance->getAsset(), - $instance->getObject(), - $instance - ); - } - - return $this->cachedData['instanceBrothers'][$instance->getId()]; - } - - private function createInstanceRiskFromData( - array $instanceRiskData, - Anr $anr, - Instance $instance, - Asset $asset, - Threat $threat, - Vulnerability $vulnerability - ): InstanceRisk { - $instanceRisk = (new InstanceRisk()) - ->setAnr($anr) - ->setInstance($instance) - ->setAsset($asset) - ->setThreat($threat) - ->setVulnerability($vulnerability) - ->setSpecific($instanceRiskData['specific']) - ->setMh((int)$instanceRiskData['mh']) - ->setThreatRate((int)$instanceRiskData['threatRate']) - ->setVulnerabilityRate((int)$instanceRiskData['vulnerabilityRate']) - ->setKindOfMeasure($instanceRiskData['kindOfMeasure']) - ->setReductionAmount((int)$instanceRiskData['reductionAmount']) - ->setComment((string)$instanceRiskData['comment']) - ->setCommentAfter((string)$instanceRiskData['commentAfter']) - ->setCacheMaxRisk((int)$instanceRiskData['cacheMaxRisk']) - ->setCacheTargetedRisk((int)$instanceRiskData['cacheTargetedRisk']) - ->setRiskConfidentiality((int)$instanceRiskData['riskC']) - ->setRiskIntegrity((int)$instanceRiskData['riskI']) - ->setRiskAvailability((int)$instanceRiskData['riskD']) - ->setContext($instanceRiskData['context'] ?? '') - ->setCreator($this->connectedUser->getEmail()); - - if (!empty($instanceRiskData['riskOwner'])) { - $instanceRiskOwner = $this->anrInstanceRiskService->getOrCreateInstanceRiskOwner( - $anr, - $instanceRiskData['riskOwner'] - ); - $instanceRisk->setInstanceRiskOwner($instanceRiskOwner); - } - - return $instanceRisk; - } - - private function createInstance( - array $data, - Anr $anr, - ?InstanceSuperClass $parentInstance, - MonarcObject $monarcObject - ): Instance { - $instanceData = $data['instance']; - $instance = (new Instance()) - ->setAnr($anr) - ->setLabels($monarcObject->getLabels()) - ->setNames($monarcObject->getNames()) - ->setDisponibility(!empty($instanceData['disponibility']) ? (float)$instanceData['disponibility'] : 0) - ->setLevel($parentInstance === null ? Instance::LEVEL_ROOT : $instanceData['level']) - ->setRoot($parentInstance === null ? null : ($parentInstance->getRoot() ?? $parentInstance)) - ->setParent($parentInstance) - ->setAssetType($instanceData['assetType']) - ->setExportable($instanceData['exportable']) - ->setPosition(++$this->currentMaxInstancePosition) - ->setObject($monarcObject) - ->setAsset($monarcObject->getAsset()) - ->setCreator($this->connectedUser->getEmail()); - if (isset($instanceData['c'])) { - $instance->setConfidentiality((int)$instanceData['c']); - } - if (isset($instanceData['i'])) { - $instance->setIntegrity((int)$instanceData['i']); - } - if (isset($instanceData['d'])) { - $instance->setAvailability((int)$instanceData['d']); - } - if (isset($instanceData['ch'])) { - $instance->setInheritedConfidentiality((int)$instanceData['ch']); - } - if (isset($instanceData['ih'])) { - $instance->setInheritedIntegrity((int)$instanceData['ih']); - } - if (isset($instanceData['dh'])) { - $instance->setInheritedAvailability((int)$instanceData['dh']); - } - - $this->instanceTable->saveEntity($instance); - - return $instance; - } - - /** - * @throws Exception - */ - private function setAndValidateMonarcVersion($data): void - { - if (isset($data['monarc_version'])) { - $this->monarcVersion = strpos($data['monarc_version'], 'master') === false ? $data['monarc_version'] : '99'; - } - - if ($this->isMonarcVersionLoverThen('2.8.2')) { - throw new Exception('Import of files exported from MONARC v2.8.1 or lower are not supported.' - . ' Please contact us for more details.'); - } - } - - private function adjustOperationalRisksScaleValuesBasedOnNewScales(Anr $anr, array $data): void - { - $operationalInstanceRisks = $this->instanceRiskOpTable->findByAnr($anr); - if (!empty($operationalInstanceRisks)) { - $currentOperationalRiskScalesData = $this->getCurrentOperationalRiskScalesData($anr); - $externalOperationalRiskScalesData = $this->getExternalOperationalRiskScalesData($anr, $data); - - foreach ($operationalInstanceRisks as $operationalInstanceRisk) { - $this->adjustOperationalRisksProbabilityScales( - $operationalInstanceRisk, - $currentOperationalRiskScalesData[OperationalRiskScale::TYPE_LIKELIHOOD], - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_LIKELIHOOD] - ); - - foreach ($operationalInstanceRisk->getOperationalInstanceRiskScales() as $instanceRiskScale) { - $this->adjustOperationalInstanceRisksScales( - $instanceRiskScale, - $currentOperationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT], - $externalOperationalRiskScalesData[OperationalRiskScale::TYPE_IMPACT] - ); - } - - $this->instanceRiskOpTable->saveEntity($operationalInstanceRisk, false); - - $this->anrInstanceRiskOpService->updateRiskCacheValues($operationalInstanceRisk); - } - - $this->instanceRiskOpTable->getDb()->flush(); - } - } - - private function adjustOperationalRisksProbabilityScales( - InstanceRiskOp $operationalInstanceRisk, - array $fromOperationalRiskScalesData, - array $toOperationalRiskScalesData - ): void { - foreach (['NetProb', 'BrutProb', 'TargetedProb'] as $likelihoodScaleName) { - $operationalInstanceRisk->{'set' . $likelihoodScaleName}($this->approximate( - $operationalInstanceRisk->{'get' . $likelihoodScaleName}(), - $fromOperationalRiskScalesData['min'], - $fromOperationalRiskScalesData['max'], - $toOperationalRiskScalesData['min'], - $toOperationalRiskScalesData['max'] - )); - } - } - - private function adjustOperationalInstanceRisksScales( - OperationalInstanceRiskScale $instanceRiskScale, - array $fromOperationalRiskScalesData, - array $toOperationalRiskScalesData - ): void { - foreach (['NetValue', 'BrutValue', 'TargetedValue'] as $impactScaleName) { - $scaleImpactValue = $instanceRiskScale->{'get' . $impactScaleName}(); - if ($scaleImpactValue === -1) { - continue; - } - $scaleImpactIndex = array_search( - $scaleImpactValue, - $fromOperationalRiskScalesData['commentsIndexToValueMap'], - true - ); - if ($scaleImpactIndex === false) { - continue; - } - - $approximatedIndex = $this->approximate( - $scaleImpactIndex, - $fromOperationalRiskScalesData['min'], - $fromOperationalRiskScalesData['max'], - $toOperationalRiskScalesData['min'], - $toOperationalRiskScalesData['max'] - ); - - $approximatedValueToNewScales = $toOperationalRiskScalesData['commentsIndexToValueMap'][$approximatedIndex] - ?? $scaleImpactValue; - $instanceRiskScale->{'set' . $impactScaleName}($approximatedValueToNewScales); - - $this->operationalInstanceRiskScaleTable->save($instanceRiskScale, false); - } - } - - private function getCurrentOperationalRiskScalesData(Anr $anr): array - { - if (empty($this->cachedData['currentOperationalRiskScalesData'])) { - $operationalRisksScales = $this->operationalRiskScaleTable->findByAnr($anr); - foreach ($operationalRisksScales as $operationalRisksScale) { - $scaleTypesData = []; - $commentsIndexToValueMap = []; - /* Build the map of the comments index <=> values relation. */ - foreach ($operationalRisksScale->getOperationalRiskScaleTypes() as $typeIndex => $scaleType) { - /* The operational risk scale types object is used to recreate operational instance risk scales. */ - $scaleTypesData[$typeIndex]['object'] = $scaleType; - /* All the scale comment have the same index -> value corresponding values, so populating once. */ - if (empty($commentsIndexToValueMap)) { - foreach ($scaleType->getOperationalRiskScaleComments() as $scaleTypeComment) { - if (!$scaleTypeComment->isHidden()) { - $commentsIndexToValueMap[$scaleTypeComment->getScaleIndex()] = - $scaleTypeComment->getScaleValue(); - } - } - } - } - - $this->cachedData['currentOperationalRiskScalesData'][$operationalRisksScale->getType()] = [ - 'min' => $operationalRisksScale->getMin(), - 'max' => $operationalRisksScale->getMax(), - 'object' => $operationalRisksScale, - 'commentsIndexToValueMap' => $commentsIndexToValueMap, - 'operationalRiskScaleTypes' => $scaleTypesData, - 'operationalRiskScaleComments' => $operationalRisksScale->getOperationalRiskScaleComments(), - ]; - } - } - - return $this->cachedData['currentOperationalRiskScalesData']; - } - - /** - * Prepare and cache the new scales for the future use. - * The format can be different, depends on the version (before v2.11.0 and after). - */ - private function getExternalOperationalRiskScalesData(Anr $anr, array $data): array - { - if (empty($this->cachedData['externalOperationalRiskScalesData'])) { - /* Populate with informational risks scales in case if there is an import of file before v2.11.0. */ - $scalesDataResult = [ - OperationalRiskScale::TYPE_IMPACT => [ - 'min' => 0, - 'max' => $data['scales'][Scale::TYPE_IMPACT]['max'] - $data['scales'][Scale::TYPE_IMPACT]['min'], - 'commentsIndexToValueMap' => [], - 'operationalRiskScaleTypes' => [], - 'operationalRiskScaleComments' => [], - ], - OperationalRiskScale::TYPE_LIKELIHOOD => [ - 'min' => $data['scales'][Scale::TYPE_THREAT]['min'], - 'max' => $data['scales'][Scale::TYPE_THREAT]['max'], - 'commentsIndexToValueMap' => [], - 'operationalRiskScaleTypes' => [], - 'operationalRiskScaleComments' => [], - ], - ]; - if (!empty($data['operationalRiskScales'])) { - /* Overwrite the values for the version >= 2.10.5. */ - foreach ($data['operationalRiskScales'] as $scaleType => $operationalRiskScaleData) { - $scalesDataResult[$scaleType]['min'] = $operationalRiskScaleData['min']; - $scalesDataResult[$scaleType]['max'] = $operationalRiskScaleData['max']; - - /* Build the map of the comments index <=> values relation. */ - foreach ($operationalRiskScaleData['operationalRiskScaleTypes'] as $typeIndex => $scaleTypeData) { - $scalesDataResult[$scaleType]['operationalRiskScaleTypes'][$typeIndex] = $scaleTypeData; - /* All the scale comment have the same index->value corresponding values, so populating once. */ - if (empty($scalesDataResult[$scaleType]['commentsIndexToValueMap'])) { - foreach ($scaleTypeData['operationalRiskScaleComments'] as $scaleTypeComment) { - if (!$scaleTypeComment['isHidden']) { - $scalesDataResult[$scaleType]['commentsIndexToValueMap'] - [$scaleTypeComment['scaleIndex']] = $scaleTypeComment['scaleValue']; - } - } - } - } - - $scalesDataResult[$scaleType]['operationalRiskScaleComments'] = - $operationalRiskScaleData['operationalRiskScaleComments']; - } - } else { - /* Convert comments and types from informational risks to operational (new format). */ - $anrLanguageCode = $this->getAnrLanguageCode($anr); - $scaleMin = $data['scales'][Scale::TYPE_IMPACT]['min']; - foreach ($this->scaleImpactTypeTable->findByAnrOrderedByPosition($anr) as $index => $scaleImpactType) { - if ($scaleImpactType->isSys() - && \in_array($scaleImpactType->getType(), ScaleImpactType::getScaleImpactTypesRolfp(), true) - ) { - $labelTranslationKey = (string)Uuid::uuid4(); - $scalesDataResult[Scale::TYPE_IMPACT]['operationalRiskScaleTypes'][$index] = [ - 'id' => $scaleImpactType->getId(), - 'isHidden' => $scaleImpactType->isHidden(), - 'labelTranslationKey' => $labelTranslationKey, - 'translation' => [ - 'key' => $labelTranslationKey, - 'lang' => $anrLanguageCode, - 'value' => $scaleImpactType->getLabel($anr->getLanguage()), - ], - ]; - } - } - foreach ($data['scalesComments'] as $scaleComment) { - $scaleType = $scaleComment['scale']['type']; - if (!\in_array($scaleType, [Scale::TYPE_IMPACT, Scale::TYPE_THREAT], true)) { - continue; - } - - if ($scaleType === Scale::TYPE_THREAT) { - $commentTranslationKey = (string)Uuid::uuid4(); - $scalesDataResult[$scaleType]['operationalRiskScaleComments'][] = [ - 'id' => $scaleComment['id'], - 'scaleIndex' => $scaleComment['val'], - 'scaleValue' => $scaleComment['val'], - 'isHidden' => false, - 'commentTranslationKey' => $commentTranslationKey, - 'translation' => [ - 'key' => $commentTranslationKey, - 'lang' => $anrLanguageCode, - 'value' => $scaleComment['comment' . $anr->getLanguage()] ?? '', - ], - ]; - } elseif ($scaleType === Scale::TYPE_IMPACT && $scaleComment['val'] >= $scaleMin) { - $commentTranslationKey = (string)Uuid::uuid4(); - $scaleIndex = $scaleComment['val'] - $scaleMin; - $scaleTypePosition = $scaleComment['scaleImpactType']['position']; - if (isset($scalesDataResult[$scaleType]['operationalRiskScaleTypes'][$scaleTypePosition])) { - $scalesDataResult[$scaleType]['operationalRiskScaleTypes'][$scaleTypePosition] - ['operationalRiskScaleComments'][] = [ - 'id' => $scaleComment['id'], - 'scaleIndex' => $scaleIndex, - 'scaleValue' => $scaleComment['val'], - 'isHidden' => false, - 'commentTranslationKey' => $commentTranslationKey, - 'translation' => [ - 'key' => $commentTranslationKey, - 'lang' => $anrLanguageCode, - 'value' => $scaleComment['comment' . $anr->getLanguage()] ?? '', - ], - ]; - - $scalesDataResult[$scaleType]['commentsIndexToValueMap'][$scaleIndex] - = $scaleComment['val']; - } - } - } - } - - $this->cachedData['externalOperationalRiskScalesData'] = $scalesDataResult; - } - - return $this->cachedData['externalOperationalRiskScalesData']; - } - - private function updateScalesAndComments(Anr $anr, array $data): void - { - $scalesByType = []; - $scales = $this->scaleTable->findByAnr($anr); - foreach ([Scale::TYPE_IMPACT, Scale::TYPE_THREAT, Scale::TYPE_VULNERABILITY] as $type) { - foreach ($scales as $scale) { - if ($scale->getType() === $type) { - $scale->setMin((int)$data['scales'][$type]['min']); - $scale->setMax((int)$data['scales'][$type]['max']); - - $scalesByType[$type] = $scale; - - $this->scaleTable->saveEntity($scale, false); - } - } - } - - if (!empty($data['scalesComments'])) { - $scaleComments = $this->scaleCommentTable->findByAnr($anr); - foreach ($scaleComments as $scaleComment) { - if ($scaleComment->getScaleImpactType() === null - || $scaleComment->getScaleImpactType()->isSys() - ) { - $this->scaleCommentTable->deleteEntity($scaleComment, false); - } - } - $this->scaleCommentTable->getDb()->flush(); - - $scaleImpactTypes = $this->scaleImpactTypeTable->findByAnrOrderedAndIndexedByPosition($anr); - $scaleImpactTypeMaxPosition = $this->scaleImpactTypeTable->findMaxPositionByAnrAndScale( - $anr, - $scalesByType[Scale::TYPE_IMPACT] - ); - foreach ($data['scalesComments'] as $scalesCommentData) { - /* - * Comments, which are not matched with a scale impact type, should not be created. - * This is possible only for exported files before v2.11.0. - */ - if (isset($scalesCommentData['scaleImpactType']) - && !isset($scaleImpactTypes[$scalesCommentData['scaleImpactType']['position']]) - && !isset($scalesCommentData['scaleImpactType']['labels']) - ) { - continue; - } - - $scale = $scalesByType[$scalesCommentData['scale']['type']]; - $scaleComment = (new ScaleComment()) - ->setAnr($anr) - ->setScale($scale) - ->setScaleIndex($scalesCommentData['scaleIndex'] ?? $scalesCommentData['val']) - ->setScaleValue($scalesCommentData['scaleValue'] ?? $scalesCommentData['val']) - ->setComments([ - 'comment1' => $scalesCommentData['comment1'], - 'comment2' => $scalesCommentData['comment2'], - 'comment3' => $scalesCommentData['comment3'], - 'comment4' => $scalesCommentData['comment4'], - ]) - ->setCreator($this->connectedUser->getEmail()); - - if (isset($scalesCommentData['scaleImpactType']['position'])) { - $scaleImpactTypePosition = $scalesCommentData['scaleImpactType']['position']; - $scaleImpactType = $scaleImpactTypes[$scaleImpactTypePosition] ?? null; - $isSystem = $scaleImpactType !== null && $scaleImpactType->isSys(); - /* Scale impact types are presented in the export separately since v2.11.0 */ - if (isset($scalesCommentData['scaleImpactType']['labels']) - && !$isSystem - && ($scaleImpactType === null - || $scaleImpactType->getLabel($anr->getLanguage()) - !== $scalesCommentData['scaleImpactType']['labels']['label' . $anr->getLanguage()] - ) - ) { - $scaleImpactType = (new ScaleImpactType()) - ->setType($scalesCommentData['scaleImpactType']['type']) - ->setLabels($scalesCommentData['scaleImpactType']['labels']) - ->setIsSys($scalesCommentData['scaleImpactType']['isSys']) - ->setIsHidden($scalesCommentData['scaleImpactType']['isHidden']) - ->setAnr($anr) - ->setScale($scale) - ->setPosition(++$scaleImpactTypeMaxPosition) - ->setCreator($this->connectedUser->getEmail()); - - $this->scaleImpactTypeTable->saveEntity($scaleImpactType, false); - - $scaleImpactTypes[$scaleImpactTypePosition] = $scaleImpactType; - } - if ($scaleImpactType === null) { - continue; - } - - /* We may overwrite the comments if position is matched but scale type labels are different */ - $scaleComment->setScaleImpactType($scaleImpactType); - } - - $this->scaleCommentTable->saveEntity($scaleComment, false); - } - $this->scaleCommentTable->getDb()->flush(); - } - - /* Reset the cache */ - $this->cachedData['scales'] = []; - } - - private function updateOperationalRisksScalesAndRelatedInstances(Anr $anr, array $data): void - { - $operationalRiskScales = $this->operationalRiskScaleTable->findByAnr($anr); - $anrLanguageCode = $this->getAnrLanguageCode($anr); - $scalesTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::OPERATIONAL_RISK_SCALE_TYPE, Translation::OPERATIONAL_RISK_SCALE_COMMENT], - $anrLanguageCode - ); - $externalOperationalScalesData = $this->getExternalOperationalRiskScalesData($anr, $data); - - foreach ($operationalRiskScales as $operationalRiskScale) { - $scaleData = $externalOperationalScalesData[$operationalRiskScale->getType()]; - $currentScaleLevelDifferenceFromExternal = $operationalRiskScale->getMax() - $scaleData['max']; - $operationalRiskScale - ->setAnr($anr) - ->setMin($scaleData['min']) - ->setMax($scaleData['max']) - ->setUpdater($this->connectedUser->getEmail()); - - /* This is currently only applicable for impact scales type. */ - $createdScaleTypes = []; - $matchedScaleTypes = []; - foreach ($scaleData['operationalRiskScaleTypes'] as $scaleTypeData) { - $isScaleTypeMatched = true; - $operationalRiskScaleType = $this->matchScaleTypeDataWithScaleTypesList( - $scaleTypeData, - $operationalRiskScale->getOperationalRiskScaleTypes(), - $scalesTranslations - ); - if ($operationalRiskScaleType === null) { - $isScaleTypeMatched = false; - $labelTranslationKey = (string)Uuid::uuid4(); - $operationalRiskScaleType = (new OperationalRiskScaleType()) - ->setAnr($anr) - ->setOperationalRiskScale($operationalRiskScale) - ->setLabelTranslationKey($labelTranslationKey) - ->setCreator($this->connectedUser->getEmail()); - - $translation = (new Translation()) - ->setAnr($anr) - ->setType(Translation::OPERATIONAL_RISK_SCALE_TYPE) - ->setLang($anrLanguageCode) - ->setKey($labelTranslationKey) - ->setValue($scaleTypeData['translation']['value']) - ->setCreator($this->connectedUser->getEmail()); - $this->translationTable->save($translation, false); - - $createdScaleTypes[$labelTranslationKey] = $operationalRiskScaleType; - } elseif ($currentScaleLevelDifferenceFromExternal !== 0) { - $matchedScaleTypes[$operationalRiskScaleType->getId()] = $operationalRiskScaleType; - } - - /* The map is used to match for the importing operational risks, scale values with scale types. */ - $this->cachedData['operationalRiskScaleTypes']['currentScaleTypeLabelTranslationKeyToExternalIds'] - [$operationalRiskScaleType->getLabelTranslationKey()] = $scaleTypeData['id']; - - $operationalRiskScaleType->setIsHidden($scaleTypeData['isHidden']); - $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType, false); - - foreach ($scaleTypeData['operationalRiskScaleComments'] as $scaleTypeCommentData) { - $this->createOrUpdateOperationalRiskScaleComment( - $anr, - $isScaleTypeMatched, - $operationalRiskScale, - $scaleTypeCommentData, - $operationalRiskScaleType->getOperationalRiskScaleComments(), - $scalesTranslations, - $operationalRiskScaleType - ); - } - } - - /* Create relations of all the created scales with existed risks. */ - if (!empty($createdScaleTypes)) { - $operationalInstanceRisks = $this->instanceRiskOpTable->findByAnr($anr); - foreach ($operationalInstanceRisks as $operationalInstanceRisk) { - foreach ($createdScaleTypes as $createdScaleType) { - $operationalInstanceRiskScale = (new OperationalInstanceRiskScale()) - ->setAnr($anr) - ->setOperationalRiskScaleType($createdScaleType) - ->setOperationalInstanceRisk($operationalInstanceRisk) - ->setCreator($this->connectedUser->getEmail()); - $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); - } - } - } - - $maxIndexForLikelihood = 0; - /* This is currently applicable only for likelihood scales type */ - foreach ($scaleData['operationalRiskScaleComments'] as $scaleCommentData) { - $this->createOrUpdateOperationalRiskScaleComment( - $anr, - true, - $operationalRiskScale, - $scaleCommentData, - $operationalRiskScale->getOperationalRiskScaleComments(), - $scalesTranslations - ); - $maxIndexForLikelihood = (int)$scaleCommentData['scaleIndex'] > $maxIndexForLikelihood - ? (int)$scaleCommentData['scaleIndex'] - : $maxIndexForLikelihood; - } - /* Manage a case when the scale (probability) is not matched and level higher than external. */ - if ($maxIndexForLikelihood !== 0 - && $operationalRiskScale->getType() === OperationalRiskScale::TYPE_LIKELIHOOD - ) { - foreach ($operationalRiskScale->getOperationalRiskScaleComments() as $comment) { - if ($comment->getScaleIndex() >= $maxIndexForLikelihood) { - $comment->setIsHidden(true); - $this->operationalRiskScaleCommentTable->save($comment, false); - } - } - } - - /* Validate if any existed comments are now out of the new scales bound and if their values are valid. - Also, if their comments are complete per scale's level. */ - if ($currentScaleLevelDifferenceFromExternal !== 0) { - foreach ($operationalRiskScale->getOperationalRiskScaleTypes() as $operationalRiskScaleType) { - /* Ignore the currently created scale types. */ - if (\array_key_exists($operationalRiskScaleType->getLabelTranslationKey(), $createdScaleTypes)) { - continue; - } - - if ($currentScaleLevelDifferenceFromExternal < 0 - && !\array_key_exists($operationalRiskScaleType->getId(), $matchedScaleTypes) - ) { - /* The scales type was not matched and the current scales level is lower then external, - so we need to create missing empty scales comments. */ - $commentIndex = $operationalRiskScale->getMax() + $currentScaleLevelDifferenceFromExternal + 1; - $commentIndexToValueMap = $externalOperationalScalesData[OperationalRiskScale::TYPE_IMPACT] - ['commentsIndexToValueMap']; - while ($commentIndex <= $operationalRiskScale->getMax()) { - $this->createOrUpdateOperationalRiskScaleComment( - $anr, - false, - $operationalRiskScale, - [ - 'scaleIndex' => $commentIndex, - 'scaleValue' => $commentIndexToValueMap[$commentIndex], - 'isHidden' => false, - 'translation' => [ - 'value' => '', - ], - ], - [], - [], - $operationalRiskScaleType - ); - $commentIndex++; - } - - continue; - } - - if ($currentScaleLevelDifferenceFromExternal > 0) { - $commentIndexToValueMap = $externalOperationalScalesData[OperationalRiskScale::TYPE_IMPACT] - ['commentsIndexToValueMap']; - $maxValue = $commentIndexToValueMap[$operationalRiskScale->getMax()]; - if (\array_key_exists($operationalRiskScaleType->getId(), $matchedScaleTypes)) { - /* The scales type was matched and the current scales level is higher then external, - so we need to hide their comments and validate values. */ - foreach ($matchedScaleTypes as $matchedScaleType) { - foreach ($matchedScaleType->getOperationalRiskScaleComments() as $comment) { - $isHidden = $operationalRiskScale->getMin() > $comment->getScaleIndex() - || $operationalRiskScale->getMax() < $comment->getScaleIndex(); - $comment->setIsHidden($isHidden); - if ($isHidden && $maxValue >= $comment->getScaleValue()) { - $comment->setScaleValue(++$maxValue); - } - - $this->operationalRiskScaleCommentTable->save($comment, false); - } - } - } else { - /* Manage a case when the scale is not matched and level higher than external */ - foreach ($operationalRiskScaleType->getOperationalRiskScaleComments() as $comment) { - $isHidden = $operationalRiskScale->getMin() > $comment->getScaleIndex() - || $operationalRiskScale->getMax() < $comment->getScaleIndex(); - $comment->setIsHidden($isHidden); - if ($isHidden && $maxValue >= $comment->getScaleValue()) { - $comment->setScaleValue(++$maxValue); - } - - $this->operationalRiskScaleCommentTable->save($comment, false); - } - } - } - } - } - - $this->operationalRiskScaleTable->save($operationalRiskScale); - } - - /* Reset the cache */ - $this->cachedData['currentOperationalRiskScalesData'] = []; - } - - private function createOrUpdateOperationalRiskScaleComment( - Anr $anr, - bool $isMatchRequired, - OperationalRiskScale $operationalRiskScale, - array $scaleCommentData, - iterable $scaleCommentsToMatchWith, - array $scalesTranslations, - ?OperationalRiskScaleType $operationalRiskScaleType = null - ): void { - $operationalRiskScaleComment = null; - if ($isMatchRequired) { - $operationalRiskScaleComment = $this->matchScaleCommentDataWithScaleCommentsList( - $operationalRiskScale, - $scaleCommentData, - $scaleCommentsToMatchWith, - $scalesTranslations - ); - } - if ($operationalRiskScaleComment === null) { - $anrLanguageCode = $this->getAnrLanguageCode($anr); - $commentTranslationKey = (string)Uuid::uuid4(); - $operationalRiskScaleComment = (new OperationalRiskScaleComment()) - ->setAnr($anr) - ->setOperationalRiskScale($operationalRiskScale) - ->setCommentTranslationKey($commentTranslationKey) - ->setCreator($this->connectedUser->getEmail()); - - $translation = (new Translation()) - ->setAnr($anr) - ->setType(Translation::OPERATIONAL_RISK_SCALE_COMMENT) - ->setLang($anrLanguageCode) - ->setKey($commentTranslationKey) - ->setValue($scaleCommentData['translation']['value']) - ->setCreator($this->connectedUser->getEmail()); - $this->translationTable->save($translation, false); - } - - if ($operationalRiskScaleType !== null) { - $operationalRiskScaleComment->setOperationalRiskScaleType($operationalRiskScaleType); - } - - $operationalRiskScaleComment - ->setScaleIndex($scaleCommentData['scaleIndex']) - ->setScaleValue($scaleCommentData['scaleValue']) - ->setIsHidden($scaleCommentData['isHidden']); - $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); - } - - /** - * @param array $scaleTypeData - * @param OperationalRiskScaleType[] $operationalRiskScaleTypes - * @param Translation[] $scalesTranslations - * - * @return OperationalRiskScaleType|null - */ - private function matchScaleTypeDataWithScaleTypesList( - array $scaleTypeData, - iterable $operationalRiskScaleTypes, - array $scalesTranslations - ): ?OperationalRiskScaleType { - foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { - if (isset($scalesTranslations[$operationalRiskScaleType->getLabelTranslationKey()])) { - $translation = $scalesTranslations[$operationalRiskScaleType->getLabelTranslationKey()]; - if ($translation->getValue() === $scaleTypeData['translation']['value']) { - return $operationalRiskScaleType; - } - } - } - - return null; - } - - private function matchScaleCommentDataWithScaleCommentsList( - OperationalRiskScale $operationalRiskScale, - array $scaleTypeCommentData, - iterable $operationalRiskScaleComments, - array $scalesTranslations - ): ?OperationalRiskScaleComment { - foreach ($operationalRiskScaleComments as $operationalRiskScaleComment) { - if ($operationalRiskScale->getId() !== $operationalRiskScaleComment->getOperationalRiskScale()->getId()) { - continue; - } - if ($operationalRiskScaleComment->getScaleIndex() === $scaleTypeCommentData['scaleIndex']) { - $translation = $scalesTranslations[$operationalRiskScaleComment->getCommentTranslationKey()]; - if ($translation->getValue() !== $scaleTypeCommentData['translation']['value']) { - /* We need to update the translation value. */ - $translation->setValue($scaleTypeCommentData['translation']['value']); - $this->translationTable->save($translation, false); - } - - return $operationalRiskScaleComment; - } - } - - return null; - } - - private function getAnrLanguageCode(Anr $anr): string - { - return strtolower($this->configService->getLanguageCodes()[$anr->getLanguage()]); - } - - private function createInstanceMetadata(InstanceSuperClass $instance, $data): void - { - $anr = $instance->getAnr(); - $anrLanguageCode = $this->getAnrLanguageCode($anr); - //fetch translations - $instanceMetadataTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::INSTANCE_METADATA], - $anrLanguageCode - ); - if (isset($data['instancesMetadatas'])) { - if (!isset($this->cachedData['anrMetadataOnInstances'])) { - $this->cachedData['anrMetadataOnInstances'] = - $this->getCurrentAnrMetadataOnInstances($anr); - } - // initialize the metadatas labels - $labels = array_column($this->cachedData['anrMetadataOnInstances'], 'label'); - foreach ($data['instancesMetadatas'] as $instanceMetadata) { - if (!in_array($instanceMetadata['label'], $labels)) { - $this->createAnrMetadataOnInstances($anr, [$instanceMetadata]); - //update after insertion - $labels = array_column($this->cachedData['anrMetadataOnInstances'], 'label'); - } - // if the metadata exist we can create/update the instanceMetadata - if (in_array($instanceMetadata['label'], $labels)) { - $indexMetadata = array_search($instanceMetadata['label'], $labels); - $metadata = $this->cachedData['anrMetadataOnInstances'][$indexMetadata]['object']; - $instanceMetadataObject = $this->instanceMetadataTable->findByInstanceAndMetadata( - $instance, - $metadata - ); - if ($instanceMetadataObject === null) { - $commentTranslationKey = (string)Uuid::uuid4(); - $instanceMetadataObject = (new InstanceMetadata()) - ->setInstance($instance) - ->setMetadata($metadata) - ->setCommentTranslationKey($commentTranslationKey) - ->setCreator($this->connectedUser->getEmail()); - $this->instanceMetadataTable->save($instanceMetadataObject, false); - - $translation = (new Translation()) - ->setAnr($anr) - ->setType(Translation::INSTANCE_METADATA) - ->setKey($commentTranslationKey) - ->setValue($instanceMetadata['comment']) - ->setLang($anrLanguageCode) - ->setCreator($this->connectedUser->getEmail()); - $this->translationTable->save($translation, false); - $instanceMetadataTranslations[$commentTranslationKey] = $translation; - $this->updateInstanceMetadataToBrothers($instance, $instanceMetadataObject); - } else { - $commentTranslationKey = $instanceMetadataObject->getCommentTranslationKey(); - $commentTranslation = $instanceMetadataTranslations[$commentTranslationKey]; - $commentTranslation->setValue( - $commentTranslation->getValue().' '.$instanceMetadata['comment'] - ); - $this->translationTable->save($commentTranslation, false); - } - } - } - } - $this->instanceMetadataTable->flush(); - $this->updateInstanceMetadataFromBrothers($instance); - $this->instanceMetadataTable->flush(); - } - - private function createAnrMetadataOnInstances(Anr $anr, $data): void - { - $anrLanguageCode = $this->getAnrLanguageCode($anr); - $labels = array_column($this->cachedData['anrMetadataOnInstances'], 'label'); - foreach ($data as $v) { - if (!\in_array($v['label'], $labels, true)) { - $labelTranslationKey = (string)Uuid::uuid4(); - $metadata = (new AnrMetadatasOnInstances()) - ->setAnr($anr) - ->setLabelTranslationKey($labelTranslationKey) - ->setCreator($this->connectedUser->getEmail()) - ->setIsDeletable(true); - $this->anrMetadatasOnInstancesTable->save($metadata, false); - - $translation = (new Translation()) - ->setAnr($anr) - ->setType(Translation::ANR_METADATAS_ON_INSTANCES) - ->setKey($labelTranslationKey) - ->setValue($v['label']) - ->setLang($anrLanguageCode) - ->setCreator($this->connectedUser->getEmail()); - $this->translationTable->save($translation, false); - $this->cachedData['anrMetadataOnInstances'][] = - [ - 'id' => $metadata->getId(), - 'label' => $v['label'], - 'object' => $metadata, - 'translation' => $translation, - ]; - } - } - $this->anrMetadatasOnInstancesTable->flush(); - } - - private function getCurrentAnrMetadataOnInstances(Anr $anr): array - { - $this->cachedData['currentAnrMetadataOnInstances'] = []; - $anrMetadatasOnInstancesTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [TranslationSuperClass::ANR_METADATAS_ON_INSTANCES], - $this->getAnrLanguageCode($anr) - ); - - $AnrMetadatasOnInstances = $this->anrMetadatasOnInstancesTable->findByAnr($anr); - foreach ($AnrMetadatasOnInstances as $metadata) { - $translationLabel = $anrMetadatasOnInstancesTranslations[$metadata->getLabelTranslationKey()] ?? null; - $this->cachedData['currentAnrMetadataOnInstances'][] = [ - 'id' => $metadata->getId(), - 'label' => $translationLabel !== null ? $translationLabel->getValue() : '', - 'object' => $metadata, - 'translation' => $translationLabel, - ]; - } - return $this->cachedData['currentAnrMetadataOnInstances'] ?? []; - } - - /** - * Updates the instance impacts from brothers for global assets. - */ - private function updateInstanceMetadataFromBrothers(InstanceSuperClass $instance): void - { - if ($instance->getObject()->isScopeGlobal()) { - $instanceBrothers = $this->getInstanceBrothers($instance); - if (!empty($instanceBrothers)) { - // Update instanceMetadata of $instance. We use only one brother as the instanceMetadatas are the same. - $instanceBrother = current($instanceBrothers); - $instancesMetadatasFromBrother = $instanceBrother->getInstanceMetadatas(); - foreach ($instancesMetadatasFromBrother as $instanceMetadataFromBrother) { - $metadata = $instanceMetadataFromBrother->getMetadata(); - $instanceMetadata = $this->instanceMetadataTable - ->findByInstanceAndMetadata($instance, $metadata); - if ($instanceMetadata === null) { - $instanceMetadata = (new InstanceMetadata()) - ->setInstance($instance) - ->setMetadata($metadata) - ->setCommentTranslationKey($instanceMetadataFromBrother->getCommentTranslationKey()) - ->setCreator($this->connectedUser->getEmail()); - $this->instanceMetadataTable->save($instanceMetadata, false); - } - } - } - } - } - - /** - * Updates the instance impacts from instance to Brothers for global assets. - */ - private function updateInstanceMetadataToBrothers( - InstanceSuperClass $instance, - InstanceMetadata $instanceMetadata - ): void { - if ($instance->getObject()->isScopeGlobal()) { - $instanceBrothers = $this->getInstanceBrothers($instance); - if (!empty($instanceBrothers)) { - foreach ($instanceBrothers as $instanceBrother) { - $metadata = $instanceMetadata->getMetadata(); - $instanceMetadataBrother = $this->instanceMetadataTable - ->findByInstanceAndMetadata($instanceBrother, $metadata); - if ($instanceMetadataBrother === null) { - $instanceMetadataBrother = (new InstanceMetadata()) - ->setInstance($instanceBrother) - ->setMetadata($metadata) - ->setCommentTranslationKey($instanceMetadata->getCommentTranslationKey()) - ->setCreator($this->connectedUser->getEmail()); - $this->instanceMetadataTable->save($instanceMetadataBrother, false); - } - } - } - } - } - - private function getCurrentSoaScaleCommentData(Anr $anr): array - { - if (empty($this->cachedData['currentSoaScaleCommentData'])) { - $scales = $this->soaScaleCommentTable->findByAnr($anr); - foreach ($scales as $scale) { - if (!$scale->isHidden()) { - $this->cachedData['currentSoaScaleCommentData'][$scale->getScaleIndex()] = [ - 'scaleIndex' => $scale->getScaleIndex(), - 'isHidden' => $scale->isHidden(), - 'colour' => $scale->getColour(), - 'object' => $scale, - ]; - } - } - } - - return $this->cachedData['currentSoaScaleCommentData'] ?? []; - } - - private function mergeSoaScaleComment(array $newScales, Anr $anr) - { - $soaScaleCommentTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [TranslationSuperClass::SOA_SCALE_COMMENT], - $this->getAnrLanguageCode($anr) - ); - $scales = $this->soaScaleCommentTable->findByAnrIndexedByScaleIndex($anr); - // we have scales to create - if (\count($newScales) > \count($scales)) { - $anrLanguageCode = $this->getAnrLanguageCode($anr); - for ($i = \count($scales); $i < \count($newScales); $i++) { - $translationKey = (string)Uuid::uuid4(); - $translation = (new Translation()) - ->setAnr($anr) - ->setType(TranslationSuperClass::SOA_SCALE_COMMENT) - ->setKey($translationKey) - ->setValue('') - ->setLang($anrLanguageCode) - ->setCreator($this->connectedUser->getEmail()); - $this->translationTable->save($translation, false); - $soaScaleCommentTranslations[$translationKey] = $translation; - - $scales[$i] = (new SoaScaleComment()) - ->setScaleIndex($i) - ->setAnr($anr) - ->setCommentTranslationKey($translationKey) - ->setCreator($this->connectedUser->getEmail()); - $this->soaScaleCommentTable->save($scales[$i], false); - } - } - //we have scales to hide - if (\count($newScales) < \count($scales)) { - for ($i = \count($newScales); $i < \count($scales); $i++) { - $scales[$i]->setIsHidden(true); - $this->soaScaleCommentTable->save($scales[$i], false); - } - } - //we process the scales - foreach ($newScales as $id => $newScale) { - $scales[$newScale['scaleIndex']] - ->setColour($newScale['colour']) - ->setIsHidden($newScale['isHidden']); - $this->soaScaleCommentTable->save($scales[$newScale['scaleIndex']], false); - - $translationKey = $scales[$newScale['scaleIndex']]->getCommentTranslationKey(); - $translation = $soaScaleCommentTranslations[$translationKey]; - $translation->setValue($newScale['comment']); - - $this->translationTable->save($translation, false); - - $this->importCacheHelper->addItemToArrayCache( - 'newSoaScaleCommentIndexedByScale', - $scales[$newScale['scaleIndex']], - $newScale['scaleIndex'] - ); - $this->importCacheHelper - ->addItemToArrayCache('soaScaleCommentExternalIdMapToNewObject', $scales[$newScale['scaleIndex']], $id); - } - $this->soaScaleCommentTable->flush(); + return $instances; } } diff --git a/src/Import/Service/ObjectImportService.php b/src/Import/Service/ObjectImportService.php index 89a8551a..40437800 100644 --- a/src/Import/Service/ObjectImportService.php +++ b/src/Import/Service/ObjectImportService.php @@ -1,421 +1,204 @@ monarcObjectTable = $monarcObjectTable; - $this->objectObjectTable = $objectObjectTable; - $this->assetImportService = $assetImportService; - $this->rolfTagTable = $rolfTagTable; - $this->rolfRiskTable = $rolfRiskTable; - $this->measureTable = $measureTable; - $this->referentialTable = $referentialTable; - $this->objectCategoryTable = $objectCategoryTable; - $this->anrObjectCategoryTable = $anrObjectCategoryTable; - $this->connectedUser = $connectedUserService->getConnectedUser(); - $this->importCacheHelper = $importCacheHelper; - $this->soaCategoryService = $soaCategoryService; } - public function importFromArray(array $data, Anr $anr, string $modeImport = 'merge'): ?MonarcObject + public function getObjectsDataFromCommonDatabase(Entity\Anr $anr, string $filter) { - if (!isset($data['type'], $data['object']) || $data['type'] !== 'object') { - return null; - } - - $this->validateMonarcVersion($data); - - $objectData = $data['object']; - - /* The objects cache preparation is not called, because all the importing objects have to be processed. */ - $monarcObject = $this->importCacheHelper->getItemFromArrayCache('objects', $objectData['uuid']); - if ($monarcObject !== null) { - return $monarcObject; - } - - $asset = $this->assetImportService->importFromArray($this->getMonarcVersion($data), $data['asset'], $anr); - if ($asset === null) { - return null; - } - - $objectCategory = $this->importObjectCategories($data['categories'], (int)$objectData['category'], $anr); - if ($objectCategory === null) { - return null; - } - - /* Import Operational Risks. */ - $rolfTag = $this->processRolfTagAndRolfRisks($data, $anr); + /* Fetch all the objects with mode generic and specific that are linked to available clients_models. */ + $clientModelIds = $this->getLinkedSpecificModelIds(); + + $languageIndex = $anr->getLanguage(); + $objects = $this->coreMonarcObjectTable->findGenericOrSpecificByModelIdsFilteredByNamePart( + $clientModelIds, + $filter, + $languageIndex + ); - /* - * We merge objects with "local" scope or when the scope is "global" and the mode is by "merge". - * Matching criteria: name, asset type, scope, category. - */ - $objectScope = (int)$objectData['scope']; - $nameFiledKey = 'name' . $anr->getLanguage(); - $monarcObject = null; - if ($objectScope === ObjectSuperClass::SCOPE_LOCAL - || ( - $objectScope === ObjectSuperClass::SCOPE_GLOBAL - && $modeImport === 'merge' - ) - ) { - $monarcObject = $this->monarcObjectTable->findOneByAnrAssetNameScopeAndCategory( - $anr, - $nameFiledKey, - $objectData[$nameFiledKey], - $asset, - $objectScope, - $objectCategory - ); - if ($monarcObject !== null) { - $this->objectObjectTable->deleteAllByFather($monarcObject); - } - } + $result = []; + foreach ($objects as $object) { + $result[] = [ + 'uuid' => $object->getUuid(), + 'mode' => $object->getMode(), + 'scope' => $object->getScope(), + 'name' . $languageIndex => $object->getName($languageIndex), + 'label' . $languageIndex => $object->getLabel($languageIndex), + 'category' => $object->getCategory() !== null ? [ + 'id' => $object->getCategory()->getId(), + 'label' . $languageIndex => $object->getCategory()->getLabel($languageIndex), + ] : null, + 'asset' => [ + 'uuid' => $object->getAsset()->getUuid(), + 'label' . $languageIndex => $object->getAsset()->getLabel($languageIndex), + 'description' . $languageIndex => $object->getAsset()->getDescription($languageIndex), + 'type' => $object->getAsset()->getType(), + 'mode' => $object->getAsset()->getMode(), + 'status' => $object->getAsset()->getStatus(), + ], + ]; + } + + return $result; + } - if ($monarcObject === null) { - $labelKey = 'label' . $anr->getLanguage(); - $monarcObject = (new MonarcObject()) - ->setAnr($anr) - ->setAsset($asset) - ->setCategory($objectCategory) - ->setRolfTag($rolfTag) - ->addAnr($anr) - ->setMode($objectData['mode'] ?? 1) - ->setScope($objectData['scope']) - ->setLabel($labelKey, $objectData[$labelKey]) - ->setDisponibility(isset($objectData['disponibility']) ? (float)$objectData['disponibility'] : 0) - ->setPosition((int)$objectData['position']) - ->setCreator($this->connectedUser->getEmail()); - try { - $this->monarcObjectTable->findByAnrAndUuid($anr, $objectData['uuid']); - } catch (EntityNotFoundException $e) { - $monarcObject->setUuid($objectData['uuid']); + public function getObjectDataFromCommonDatabase(Entity\Anr $anr, string $uuid): array + { + $object = $this->validateAndGetObjectFromCommonDatabase($uuid); + + $languageIndex = $anr->getLanguage(); + $informationRisksData = []; + foreach ($object->getAsset()->getAmvs() as $amv) { + $informationRisksData[] = [ + 'id' => $amv->getUuid(), + 'threatLabel' . $languageIndex => $amv->getThreat()->getLabel($languageIndex), + 'vulnLabel' . $languageIndex => $amv->getVulnerability()->getLabel($languageIndex), + ]; + } + $operationalRisksData = []; + if ($object->getRolfTag() !== null && $object->getAsset()->isPrimary()) { + foreach ($object->getRolfTag()->getRisks() as $rolfRisk) { + $operationalRisksData[] = ['label' . $languageIndex => $rolfRisk->getLabel($languageIndex)]; } - - $this->setMonarcObjectName($monarcObject, $objectData, $nameFiledKey); } - $monarcObject->addAnr($anr); - - $this->monarcObjectTable->saveEntity($monarcObject); - - $this->importCacheHelper->addItemToArrayCache('objects', $monarcObject, $monarcObject->getUuid()); - - if (!empty($data['children'])) { - usort($data['children'], static function ($a, $b) { - if (isset($a['object']['position'], $b['object']['position'])) { - return $a['object']['position'] <=> $b['object']['position']; - } + return [ + 'uuid' => $object->getUuid(), + 'scope' => $object->getScope(), + 'name' . $languageIndex => $object->getName($languageIndex), + 'label' . $languageIndex => $object->getLabel($languageIndex), + 'risks' => $informationRisksData, + 'oprisks' => $operationalRisksData, + ]; + } - return 0; - }); + public function importFromCommonDatabase(Entity\Anr $anr, string $uuid, array $data): Entity\MonarcObject + { + $importMode = $data['mode'] ?? self::IMPORT_MODE_MERGE; + $object = $this->validateAndGetObjectFromCommonDatabase($uuid); - foreach ($data['children'] as $childObjectData) { - $childMonarcObject = $this->importFromArray($childObjectData, $anr, $modeImport); + $objectExportData = $this->coreObjectExportService->prepareExportData($object); - if ($childMonarcObject !== null) { - $maxPosition = $this->objectObjectTable->findMaxPositionByAnrAndFather($anr, $monarcObject); - $objectsRelation = (new ObjectObject()) - ->setAnr($anr) - ->setFather($monarcObject) - ->setChild($childMonarcObject) - ->setPosition($maxPosition + 1) - ->setCreator($this->connectedUser->getEmail()); + return $this->importFromArray($anr, $objectExportData, $importMode); + } - $this->objectObjectTable->saveEntity($objectsRelation); + public function importFromFile(Entity\Anr $anr, array $importParams): array + { + /* Mode may either be 'merge' or 'duplicate' */ + $importMode = empty($importParams['mode']) ? self::IMPORT_MODE_MERGE : $importParams['mode']; + $createdObjectsUuids = []; + $importErrors = []; + foreach ($importParams['file'] as $file) { + if (isset($file['error']) && $file['error'] === UPLOAD_ERR_OK && file_exists($file['tmp_name'])) { + $data = $this->getArrayDataOfJsonFileContent($file['tmp_name'], $importParams['password'] ?? null); + if ($data !== false) { + $object = $this->importFromArray($anr, $data, $importMode); + if ($object !== null) { + $createdObjectsUuids[] = $object->getUuid(); + } + } else { + $importErrors[] = 'The file "' . $file['name'] . '" can\'t be imported'; } } } - return $monarcObject; + return [$createdObjectsUuids, $importErrors]; } - private function importObjectCategories( - array $categories, - int $categoryId, - Anr $anr - ): ?ObjectCategory { - if (empty($categories[$categoryId])) { - return null; + public function importFromArray( + Entity\Anr $anr, + array $data, + string $importMode = self::IMPORT_MODE_MERGE + ): Entity\MonarcObject { + if (!isset($data['type'], $data['object']) || $data['type'] !== 'object') { + throw new Exception('The "object" and "type" parameters have to be passed in the import data.', 412); } - $parentCategory = $categories[$categoryId]['parent'] === null - ? null - : $this->importObjectCategories($categories, (int)$categories[$categoryId]['parent'], $anr); + $this->setAndValidateImportingDataVersion($data); - $labelKey = 'label' . $anr->getLanguage(); + $this->importCacheHelper->setArrayCacheValue('import_type', InstanceImportService::IMPORT_TYPE_OBJECT); - $objectCategory = $this->objectCategoryTable->findByAnrParentAndLabel( - $anr, - $parentCategory, - $labelKey, - $categories[$categoryId][$labelKey] - ); - - if ($objectCategory === null) { - $maxPosition = $this->objectCategoryTable->findMaxPositionByAnrAndParent($anr, $parentCategory); - $rootCategory = null; - if ($parentCategory !== null) { - $rootCategory = $parentCategory->getRoot() ?? $parentCategory; - } - $objectCategory = (new ObjectCategory()) - ->setAnr($anr) - ->setRoot($rootCategory) - ->setParent($parentCategory) - ->setLabels($categories[$categoryId]) - ->setPosition($maxPosition + 1) - ->setCreator($this->connectedUser->getEmail()); - - $this->objectCategoryTable->saveEntity($objectCategory); + /* Convert the old structure format to the new one if the import is from MOSP or importing version is below. */ + if (!empty($data['mosp']) || $this->isImportingDataVersionLowerThan('2.13.1')) { + $data = $this->adaptOldObjectDataStructureToNewFormat($data, $anr->getLanguage()); } - if ($objectCategory->getParent() === null) { - $this->checkAndCreateAnrObjectCategoryLink($objectCategory); - } + $objectCategory = $this->objectCategoryImportProcessor + ->processObjectCategoryData($anr, $data['object']['category'], $importMode); - return $objectCategory; - } - - private function checkAndCreateAnrObjectCategoryLink(ObjectCategory $objectCategory): void - { + $object = $this->objectImportProcessor->processObjectData($anr, $objectCategory, $data['object'], $importMode); + $this->monarcObjectTable->save($object); - $anrObjectCategory = $this->anrObjectCategoryTable->findOneByAnrAndObjectCategory( - $objectCategory->getAnr(), - $objectCategory - ); - if ($anrObjectCategory === null) { - $maxPosition = $this->anrObjectCategoryTable->findMaxPositionByAnr($objectCategory->getAnr()); - $this->anrObjectCategoryTable->saveEntity( - (new AnrObjectCategory()) - ->setAnr($objectCategory->getAnr()) - ->setCategory($objectCategory) - ->setPosition($maxPosition + 1) - ->setCreator($this->connectedUser->getEmail()) - ); - } + return $object; } - private function processRolfTagAndRolfRisks(array $data, Anr $anr): ?RolfTag + private function validateAndGetObjectFromCommonDatabase(string $uuid): CoreMonarcObject { - if (empty($data['object']['rolfTag']) || empty($data['rolfTags'][$data['object']['rolfTag']])) { - return null; - } - - $rolfTagData = $data['rolfTags'][(int)$data['object']['rolfTag']]; - $rolfTag = $this->importCacheHelper->getItemFromArrayCache('rolfTags', $rolfTagData['code']); - if ($rolfTag !== null) { - return $rolfTag; - } - - $rolfTag = $this->rolfTagTable->findByAnrAndCode($anr, $rolfTagData['code']); - if ($rolfTag === null) { - $rolfTag = (new RolfTag()) - ->setAnr($anr) - ->setCode($rolfTagData['code']) - ->setLabels($rolfTagData) - ->setCreator($this->connectedUser->getEmail()); - } - - if (!empty($rolfTagData['risks'])) { - foreach ($rolfTagData['risks'] as $riskId) { - if (!isset($data['rolfRisks'][$riskId])) { - continue; - } - - $rolfRiskData = $data['rolfRisks'][$riskId]; - $rolfRiskCode = (string)$rolfRiskData['code']; - $rolfRisk = $this->importCacheHelper->getItemFromArrayCache('rolf_risks_by_old_ids', $riskId); - if ($rolfRisk === null) { - $rolfRisk = $this->rolfRiskTable->findByAnrAndCode($anr, $rolfRiskCode); - if ($rolfRisk === null) { - $rolfRisk = (new RolfRisk()) - ->setAnr($anr) - ->setCode($rolfRiskCode) - ->setLabels($rolfRiskData) - ->setDescriptions($rolfRiskData) - ->setCreator($this->connectedUser->getEmail()); - } - - if (!empty($rolfRiskData['measures'])) { - $this->processMeasuresAndReferentialData($anr, $rolfRisk, $rolfRiskData['measures']); + /** @var CoreMonarcObject $object */ + $object = $this->coreMonarcObjectTable->findByUuid($uuid); + + /* If the object is specific, the model's access has to be validated. */ + if ($object->isModeSpecific()) { + $clientModelIds = $this->getLinkedSpecificModelIds(); + $isObjectLinkedToAvailableSpecificModel = false; + if (!empty($clientModelIds)) { + foreach ($object->getAnrs() as $linkedAnr) { + if (\in_array($linkedAnr->getModel()->getId(), $clientModelIds, true)) { + $isObjectLinkedToAvailableSpecificModel = true; } - - $this->rolfRiskTable->saveEntity($rolfRisk, false); - - /* The cache with IDs is required to link them with operational risks in InstanceImportService. */ - $this->importCacheHelper->addItemToArrayCache('rolf_risks_by_old_ids', $rolfRisk, (int)$riskId); } - - $rolfTag->addRisk($rolfRisk); } - } - - $this->rolfTagTable->saveEntity($rolfTag, false); - - $this->importCacheHelper->addItemToArrayCache('rolfTags', $rolfTag, $rolfTagData['code']); - - return $rolfTag; - } - - private function setMonarcObjectName( - ObjectSuperClass $monarcObject, - array $objectData, - string $nameFiledKey, - int $index = 1 - ): ObjectSuperClass { - $existedObject = $this->monarcObjectTable->findOneByAnrCategoryAndName( - $monarcObject->getAnr(), - $monarcObject->getCategory(), - $nameFiledKey, - $objectData[$nameFiledKey] - ); - if ($existedObject !== null) { - if (strpos($objectData[$nameFiledKey], ' - Imp. #') !== false) { - $objectData[$nameFiledKey] = preg_replace('/#\d+/', '#' . $index, $objectData[$nameFiledKey]); - } else { - $objectData[$nameFiledKey] .= ' - Imp. #' . $index; + if (!$isObjectLinkedToAvailableSpecificModel) { + throw new Exception('Asset was not found.', 412); } - - return $this->setMonarcObjectName($monarcObject, $objectData, $nameFiledKey, $index + 1); - } - - return $monarcObject->setName($nameFiledKey, $objectData[$nameFiledKey]); - } - - private function getMonarcVersion(array $data): string - { - if (isset($data['monarc_version'])) { - return strpos($data['monarc_version'], 'master') === false ? $data['monarc_version'] : '99'; } - return '1'; + return $object; } - /** - * @throws Exception - */ - private function validateMonarcVersion(array $data): void + private function getLinkedSpecificModelIds(): array { - if (version_compare($this->getMonarcVersion($data), '2.8.2') < 0) { - throw new Exception( - 'Import of files exported from MONARC v2.8.1 or lower are not supported.' - . ' Please contact us for more details.' - ); - } - } - - private function processMeasuresAndReferentialData(Anr $anr, RolfRisk $rolfRisk, array $measuresData): void - { - $labelKey = 'label' . $anr->getLanguage(); - foreach ($measuresData as $measureData) { - /* Backward compatibility. Prior v2.10.3 measures data were not exported. */ - $measureUuid = $measureData['uuid'] ?? $measureData; - $measure = $this->importCacheHelper->getItemFromArrayCache('measures', $measureUuid) - ?: $this->measureTable->findByAnrAndUuid($anr, $measureUuid); - - if ($measure === null && isset($measureData['referential'], $measureData['category'])) { - $referentialUuid = $measuresData['referential']['uuid']; - $referential = $this->importCacheHelper->getItemFromArrayCache('referentials', $referentialUuid) - ?: $this->referentialTable->findByAnrAndUuid($anr, $referentialUuid); - - if ($referential === null) { - $referential = (new Referential()) - ->setAnr($anr) - ->setUuid($referentialUuid) - ->setCreator($this->connectedUser->getEmail()) - ->{'setLabel' . $anr->getLanguage()}($measureData['referential'][$labelKey]); - - $this->referentialTable->saveEntity($referential, false); - - $this->importCacheHelper->addItemToArrayCache('referentials', $referential, $referentialUuid); - } - - $soaCategory = $this->soaCategoryService->getOrCreateSoaCategory( - $this->importCacheHelper, - $anr, - $referential, - $measureData['category'][$labelKey] ?? '' - ); - - $measure = (new Measure()) - ->setAnr($anr) - ->setUuid($measureUuid) - ->setCategory($soaCategory) - ->setReferential($referential) - ->setCode($measureData['code']) - ->setLabels($measureData) - ->setCreator($this->connectedUser->getEmail()); - - $this->importCacheHelper->addItemToArrayCache('measures', $measure, $measureUuid); - } - - if ($measure !== null) { - $measure->addOpRisk($rolfRisk); - - $this->measureTable->saveEntity($measure, false); + $client = $this->clientTable->findFirstClient(); + $clientModelIds = []; + if ($client !== null) { + foreach ($client->getClientModels() as $clientModel) { + $clientModelIds[] = $clientModel->getModelId(); } } + + return $clientModelIds; } } diff --git a/src/Import/Traits/EvaluationConverterTrait.php b/src/Import/Traits/EvaluationConverterTrait.php new file mode 100644 index 00000000..d3cd650b --- /dev/null +++ b/src/Import/Traits/EvaluationConverterTrait.php @@ -0,0 +1,41 @@ + $typeOfScaleImpactType, + 'label' => $scalesCommentData['scaleImpactType']['labels']['label' . $languageIndex], + 'isSys' => $scalesCommentData['scaleImpactType']['isSys'], + 'isHidden' => $scalesCommentData['scaleImpactType']['isHidden'], + ]; + } + $newStructure[$scaleType]['scaleImpactTypes'][$typeOfScaleImpactType]['scaleComments'][] = [ + 'scaleIndex' => $scalesCommentData['scaleIndex'], + 'scaleValue' => $scalesCommentData['scaleValue'], + 'comment' => $scalesCommentData['comment' . $languageIndex], + ]; + $newStructure[$scaleType]['scaleComments'] = []; + } else { + $newStructure[$scaleType]['scaleImpactTypes'] = []; + $newStructure[$scaleType]['scaleComments'][] = [ + 'scaleIndex' => $scalesCommentData['scaleIndex'], + 'scaleValue' => $scalesCommentData['scaleValue'], + 'comment' => $scalesCommentData['comment' . $languageIndex], + ]; + } + } + } + + return $newStructure; + } + + public function adaptOldSoaScaleCommentsToNewFormat(array $soaScaleCommentsData): array + { + $newStructure = []; + foreach ($soaScaleCommentsData as $scaleCommentData) { + $newStructure[$scaleCommentData['scaleIndex']] = $scaleCommentData; + } + + return $newStructure; + } + + public function adaptOldSoasToNewFormatWithSoaScaleCommentIndex(array $data): array + { + $newStructure = []; + foreach ($data['soas'] as $soaData) { + $newStructure[] = array_merge($soaData, isset($soaData['soaScaleComment']) ? [ + 'soaScaleCommentIndex' => $data['soaScaleComment'][$soaData['soaScaleComment']]['scaleIndex'] ?? -1, + ] : []); + } + + return $newStructure; + } + + /** Converts all the instance related data from the structure prior v2.13.1 to the new one. */ + public function adaptOldInstanceDataToNewFormat(array $data, int $languageIndex): array + { + return [ + 'name' => $data['instance']['name' . $languageIndex], + 'label' => $data['instance']['label' . $languageIndex], + 'level' => $data['instance']['level'], + 'position' => $data['instance']['position'], + 'confidentiality' => $data['instance']['c'], + 'integrity' => $data['instance']['i'], + 'availability' => $data['instance']['d'], + 'isConfidentialityInherited' => $data['instance']['ch'], + 'isIntegrityInherited' => $data['instance']['ih'], + 'isAvailabilityInherited' => $data['instance']['dh'], + 'asset' => $data['object']['asset']['asset'], + 'object' => $this->adaptOldObjectDataStructureToNewFormat($data['object'], $languageIndex)['object'], + 'instanceMetadata' => $this->prepareInstanceMetadataData($data), + 'instanceRisks' => $this->prepareInstanceRisksData($data, $languageIndex), + 'operationalInstanceRisks' => $this->prepareOperationalInstanceRisksData($data, $languageIndex), + 'instancesConsequences' => $this->prepareInstanceConsequencesData($data, $languageIndex), + 'children' => $this->prepareChildrenInstancesData($data, $languageIndex), + ]; + } + + /** Converts all the object's related data from the structure prior v2.13.1 to the new one. */ + public function adaptOldObjectDataStructureToNewFormat(array $data, int $languageIndex): array + { + $newStructure['object'] = [ + 'uuid' => $data['object']['uuid'], + 'name' => $data['object']['name' . $languageIndex], + 'label' => $data['object']['label' . $languageIndex], + 'mode' => $data['object']['mode'], + 'scope' => $data['object']['scope'], + ]; + $newStructure['object']['category'] = $this->adaptOldCategoryStructureToNewFormat($data); + $newStructure['object']['asset'] = $data['asset']['asset']; + $newStructure['object']['asset']['informationRisks'] = []; + foreach ($data['asset']['amvs'] ?? [] as $amvData) { + $threatData = $data['asset']['threats'][$amvData['threat']]; + $threatData['theme'] = !empty($data['asset']['themes'][$threatData['theme'] ?? -1]) + ? $data['asset']['themes'][$threatData['theme']] + : null; + $measuresData = []; + foreach ($amvData['measures'] ?? [] as $measureUuid) { + if (!empty($data['asset']['measures'][$measureUuid])) { + $measuresData[] = $data['asset']['measures'][$measureUuid]; + } + } + + $newStructure['object']['asset']['informationRisks'][] = [ + 'uuid' => $amvData['uuid'], + 'asset' => $data['asset']['asset'], + 'threat' => $threatData, + 'vulnerability' => $data['asset']['vuls'][$amvData['vulnerability']], + 'measures' => $measuresData, + 'status' => $amvData['status'], + ]; + } + $newStructure['object']['rolfTag'] = null; + if (isset($data['object']['rolfTag']) && !empty($data['rolfTags'][$data['object']['rolfTag']])) { + $newStructure['object']['rolfTag'] = $data['rolfTags'][$data['object']['rolfTag']]; + $newStructure['object']['rolfTag']['rolfRisks'] = []; + foreach ($newStructure['object']['rolfTag']['risks'] ?? [] as $rolfRiskId) { + if (!empty($data['object']['rolfRisks'][$rolfRiskId])) { + $rolfRiskData = $data['object']['rolfRisks'][$rolfRiskId]; + $measuresData = []; + foreach ($rolfRiskData['measures'] ?? [] as $measureUuid) { + if (!empty($data['asset']['measures'][$measureUuid])) { + $measuresData[] = $data['asset']['measures'][$measureUuid]; + } + } + $rolfRiskData['measures'] = $measuresData; + $newStructure['object']['rolfTag']['rolfRisks'][] = $rolfRiskData; + } + } + } + $newStructure['object']['children'] = []; + foreach ($data['children'] ?? [] as $childObjectData) { + $newStructure['object']['children'][] = $this->adaptOldObjectDataStructureToNewFormat( + $childObjectData, + $languageIndex + )['object']; + } + + return $newStructure; + } + + public function adaptOldRecommendationSetsDataToNewFormat(array $data): array + { + $recommendationSetsData = []; + foreach ($data['recs'] as $recommendationData) { + $recommendationSetUuid = $recommendationData['recommandationSet']; + if (!isset($recommendationSetsData[$recommendationSetUuid])) { + $recommendationSetsData[$recommendationSetUuid] = $data['recSets'][$recommendationSetUuid]; + $recommendationSetsData[$recommendationSetUuid]['recommendations'] = []; + } + $recommendationSetsData[$recommendationSetUuid]['recommendations'][] = $recommendationData; + } + + return $recommendationSetsData; + } + + private function adaptOldCategoryStructureToNewFormat(array $data): array + { + $newCategoryStructure = []; + if (isset($data['object']['category'], $data['categories'][$data['object']['category']])) { + $newCategoryStructure = $data['categories'][$data['object']['category']]; + $newCategoryStructure['parent'] = $this + ->prepareNewStructureOfParentsHierarchy($data['categories'], (int)$newCategoryStructure['parent']); + } + + return $newCategoryStructure; + } + + private function prepareNewStructureOfParentsHierarchy(array $categoriesData, int $parentId): ?array + { + $parentCategoryData = null; + if (!empty($categoriesData[$parentId])) { + $parentCategoryData = $categoriesData[$parentId]; + $parentCategoryData['parent'] = $this + ->prepareNewStructureOfParentsHierarchy($categoriesData, (int)$parentCategoryData['parent']); + } + + return $parentCategoryData; + } + + private function prepareInstanceMetadataData(array $data): array + { + $instanceMetadataData = []; + foreach ($data['instancesMetadatas'] ?? [] as $metadataFiledId => $instanceMetadataDatum) { + if (isset($data['anrMetadatasOnInstances'][$metadataFiledId]['label'])) { + $instanceMetadataData[] = [ + 'comment' => $instanceMetadataDatum['comment'], + 'anrInstanceMetadataField' => [ + 'label' => $data['anrMetadatasOnInstances'][$metadataFiledId]['label'], + ], + ]; + } + } + + return $instanceMetadataData; + } + + private function prepareInstanceRisksData(array $data, int $languageIndex): array + { + $instanceRisksData = []; + foreach ($data['risks'] ?? [] as $instanceRiskDatum) { + $informationRiskData = null; + $threatData = $data['threats'][$instanceRiskDatum['threat']] ?? ['uuid' => $instanceRiskDatum['threat']]; + if (!empty($threatData['theme'])) { + $threatData['theme'] = $data['object']['asset']['themes'][$threatData['theme']]; + } + $vulnerabilityData = $data['vuls'][$instanceRiskDatum['vulnerability']] ?? [ + 'uuid' => $instanceRiskDatum['vulnerability'] + ]; + if (!empty($instanceRiskDatum['amv']) && isset($data['amvs'][$instanceRiskDatum['amv']])) { + $measuresData = []; + foreach ($data['amvs'][$instanceRiskDatum['amv']]['measures'] ?? [] as $measureUuid) { + if (!empty($data['measures'][$measureUuid])) { + $measuresData[] = $data['measures'][$measureUuid]; + } + } + $informationRiskData = [ + 'uuid' => $instanceRiskDatum['amv'], + 'asset' => $data['object']['asset']['asset'], + 'threat' => $threatData, + 'vulnerability' => $vulnerabilityData, + 'measures' => $measuresData, + 'status' => $data['amvs'][$instanceRiskDatum['amv']]['status'], + ]; + } + $recommendationsData = []; + if (!empty($data['recos'][$instanceRiskDatum['id']])) { + foreach ($data['recos'][$instanceRiskDatum['id']] as $recommendationData) { + $recommendationsData[] = $this->prepareRecommendationData( + $data, + $recommendationData, + $instanceRiskDatum['kindOfMeasure'] !== InstanceRiskSuperClass::KIND_NOT_TREATED, + $languageIndex + ); + } + } + + $instanceRisksData[] = [ + 'informationRisk' => $informationRiskData, + 'threat' => $threatData, + 'vulnerability' => $vulnerabilityData, + 'specific' => $instanceRiskDatum['specific'], + 'isThreatRateNotSetOrModifiedExternally' => $instanceRiskDatum['mh'], + 'threatRate' => $instanceRiskDatum['threatRate'], + 'vulnerabilityRate' => $instanceRiskDatum['vulnerabilityRate'], + 'kindOfMeasure' => $instanceRiskDatum['kindOfMeasure'], + 'reductionAmount' => $instanceRiskDatum['reductionAmount'], + 'comment' => $instanceRiskDatum['comment'], + 'commentAfter' => $instanceRiskDatum['commentAfter'], + 'cacheMaxRisk' => $instanceRiskDatum['cacheMaxRisk'], + 'cacheTargetedRisk' => $instanceRiskDatum['cacheTargetedRisk'], + 'riskConfidentiality' => $instanceRiskDatum['riskC'], + 'riskIntegrity' => $instanceRiskDatum['riskI'], + 'riskAvailability' => $instanceRiskDatum['riskD'], + 'context' => $instanceRiskDatum['context'], + 'riskOwner' => $instanceRiskDatum['riskOwner'], + 'recommendations' => $recommendationsData, + ]; + } + + return $instanceRisksData; + } + + private function prepareInstanceConsequencesData(array $data, int $languageIndex): array + { + $instanceConsequencesData = []; + foreach ($data['consequences'] as $consequenceData) { + $instanceConsequencesData[] = [ + 'confidentiality' => $consequenceData['c'], + 'integrity' => $consequenceData['i'], + 'availability' => $consequenceData['d'], + 'isHidden' => (bool)$consequenceData['isHidden'], + 'scaleImpactType' => [ + 'type' => $consequenceData['scaleImpactType']['type'], + 'label' => $consequenceData['scaleImpactType']['label' . $languageIndex], + 'isSys' => (bool)$consequenceData['scaleImpactType']['isSys'], + 'isHidden' => (bool)$consequenceData['scaleImpactType']['isHidden'], + 'scaleComments' => [], + 'scale' => [ + 'id' => (int)($consequenceData['scale'] ?? 0), + 'type' => ScaleSuperClass::TYPE_IMPACT, + ], + ], + ]; + } + + return $instanceConsequencesData; + } + + private function prepareChildrenInstancesData(array $data, int $languageIndex): array + { + $childInstancesData = []; + foreach ($data['children'] as $childInstanceData) { + $childInstancesData[] = $this->adaptOldInstanceDataToNewFormat($childInstanceData, $languageIndex); + } + + return $childInstancesData; + } + + private function prepareOperationalInstanceRisksData(array $data, int $languageIndex): array + { + $operationalInstanceRisksData = []; + foreach ($data['risksop'] as $operationalInstanceRiskData) { + $riskLabel = $operationalInstanceRiskData['riskCacheLabel' . $languageIndex]; + $rolfRiskData = null; + if (!empty($operationalInstanceRiskData['rolfRisk'])) { + foreach ($data['object']['rolfRisks'] as $rolfRiskData) { + if ($rolfRiskData['label' . $languageIndex] === $riskLabel) { + break; + } + } + $rolfTagsData = []; + foreach ($data['object']['rolfTags'] as $rolfTagData) { + if (isset($rolfTagData['risks'][$rolfRiskData['id']])) { + $rolfTagsData[] = [ + 'label' => $rolfTagData['label' . $languageIndex], + 'code' => $rolfTagData['code'], + ]; + } + } + $rolfRiskData['rolfTags'] = $rolfTagsData; + } + $recommendationsData = []; + if (!empty($data['recosop'][$operationalInstanceRiskData['id']])) { + foreach ($data['recosop'][$operationalInstanceRiskData['id']] as $recommendationData) { + $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'], + 'netProb' => $operationalInstanceRiskData['netProb'], + 'targetedProb' => $operationalInstanceRiskData['targetedProb'], + 'cacheBrutRisk' => $operationalInstanceRiskData['cacheBrutRisk'], + 'cacheNetRisk' => $operationalInstanceRiskData['cacheNetRisk'], + 'cacheTargetedRisk' => $operationalInstanceRiskData['cacheTargetedRisk'], + 'kindOfMeasure' => $operationalInstanceRiskData['kindOfMeasure'], + 'comment' => $operationalInstanceRiskData['comment'], + 'mitigation' => $operationalInstanceRiskData['mitigation'], + 'specific' => $operationalInstanceRiskData['specific'], + 'context' => $operationalInstanceRiskData['context'], + 'riskOwner' => $operationalInstanceRiskData['riskOwner'], + 'recommendations' => $recommendationsData, + 'operationalInstanceRiskScales' => $operationalInstanceRiskData['scalesValues'], + ]; + } + + return $operationalInstanceRisksData; + } + + private function prepareRecommendationData( + array $data, + array $recommendationData, + bool $isRiskTreated, + int $languageIndex + ): array { + $recommendationSetUuid = $recommendationData['recommandationSet'] ?? ''; + + return [ + 'uuid' => $recommendationData['uuid'], + 'code' => $recommendationData['code'], + 'description' => $recommendationData['description'], + 'importance' => $recommendationData['importance'], + 'comment' => $recommendationData['comment'], + 'status' => $recommendationData['status'], + 'responsible' => $recommendationData['responsable'], + '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/Import/Traits/ImportFileContentTrait.php b/src/Import/Traits/ImportFileContentTrait.php new file mode 100644 index 00000000..886eb8ca --- /dev/null +++ b/src/Import/Traits/ImportFileContentTrait.php @@ -0,0 +1,36 @@ +decrypt(file_get_contents($fileName), $password); + if ($decryptedResult === false) { + throw new Exception('Password is not correct.', 412); + } + + return json_decode($decryptedResult, true, 512, JSON_THROW_ON_ERROR); + } +} diff --git a/src/Import/Traits/ImportValidationTrait.php b/src/Import/Traits/ImportValidationTrait.php new file mode 100644 index 00000000..76127e25 --- /dev/null +++ b/src/Import/Traits/ImportValidationTrait.php @@ -0,0 +1,68 @@ +getLevel() === InstanceSuperClass::LEVEL_INTER || $parent->getAnr() !== $anr) + ) { + throw new Exception('Parent instance should be in the node tree and the analysis IDs are matched', 412); + } + + if ((!empty($data['with_eval']) || !empty($data['withEval'])) && empty($data['scales'])) { + throw new Exception('The importing file should include evaluation scales.', 412); + } + + if (!$this->isImportingDataVersionLowerThan('2.13.1') && $anr->getLanguageCode() !== $data['languageCode']) { + throw new Exception(sprintf( + 'The current analysis language "%s" should be the same as importing one "%s"', + $anr->getLanguageCode(), + $data['languageCode'] + ), 412); + } + } + + /** + * @throws Exception + */ + private function setAndValidateImportingDataVersion($data): void + { + if (isset($data['monarc_version'])) { + $this->importingDataVersion = !str_contains($data['monarc_version'], 'master') + ? $data['monarc_version'] + : '999'; + } + + if ($this->isImportingDataVersionLowerThan('2.8.2')) { + throw new Exception('Import of files exported from MONARC v2.8.1 or lower are not supported.' + . ' Please contact us for more details.'); + } + } + + private function isImportingDataVersionLowerThan(string $version): bool + { + if ($this->importingDataVersion === '') { + throw new \LogicException('The "monarc_version" parameter has to be defined in the file data structure.'); + } + + return version_compare($this->importingDataVersion, $version) < 0; + } +} diff --git a/src/InputFormatter/Amv/GetAmvsInputFormatter.php b/src/InputFormatter/Amv/GetAmvsInputFormatter.php new file mode 100644 index 00000000..adecdcaa --- /dev/null +++ b/src/InputFormatter/Amv/GetAmvsInputFormatter.php @@ -0,0 +1,25 @@ + [ + 'fieldName' => 'recommendationSet.uuid', + ], + 'status' => [ + 'default' => Recommendation::STATUS_ACTIVE, + 'type' => 'int', + ], + ]; + + protected static array $ignoredFilterFieldValues = ['status' => 'all']; +} diff --git a/src/InputFormatter/RecommendationRisk/GetRecommendationRisksInputFormatter.php b/src/InputFormatter/RecommendationRisk/GetRecommendationRisksInputFormatter.php new file mode 100644 index 00000000..b732e801 --- /dev/null +++ b/src/InputFormatter/RecommendationRisk/GetRecommendationRisksInputFormatter.php @@ -0,0 +1,32 @@ + [ + 'fieldName' => 'recommendation.uuid', + ], + 'instanceRisk' => [ + 'type' => 'int', + 'fieldName' => 'instanceRisk.id' + ], + 'instanceRiskOp' => [ + 'type' => 'int', + 'fieldName' => 'instanceRiskOp.id' + ], + 'includeRelations' => [ + 'type' => 'bool', + 'isUsedInQuery' => false, + ], + ]; +} diff --git a/src/InputFormatter/Soa/GetSoasInputFormatter.php b/src/InputFormatter/Soa/GetSoasInputFormatter.php new file mode 100644 index 00000000..5fe15da6 --- /dev/null +++ b/src/InputFormatter/Soa/GetSoasInputFormatter.php @@ -0,0 +1,41 @@ + [ + 'fieldName' => 'measure.referential.uuid', + 'relationConditions' => [ + 'measure.anr = :anr', + 'referential.anr = :anr', + ], + ], + 'category' => [ + 'fieldName' => 'measure.category', + ], + ]; + + protected static array $ignoredFilterFieldValues = ['category' => '0']; + + protected static array $orderParamsToFieldsMap = [ + 'm.code' => 'measure.code|LENGTH,measure.code', + ]; +} diff --git a/src/InputFormatter/Threat/GetThreatsInputFormatter.php b/src/InputFormatter/Threat/GetThreatsInputFormatter.php new file mode 100644 index 00000000..5228e907 --- /dev/null +++ b/src/InputFormatter/Threat/GetThreatsInputFormatter.php @@ -0,0 +1,19 @@ +getConnectedUser(); + $this->connectedUser = $connectedUser; + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + /** @var RouteMatch $routeMatch */ + $routeMatch = $request->getAttribute(RouteMatch::class); + + /* Exclude from validation getList and create of /api/client-anr/[:anrid]. */ + if ($this->isRouteAndRequestExcludedFromValidation($routeMatch, $request)) { + return $handler->handle($request); + } + + /* Retrieving anr ID from all the routes where /[:anrid]/ is presented in the route. */ + $anrId = $routeMatch->getMatchedRouteName() === 'monarc_api_client_anr' + ? (int)$routeMatch->getParam('id') + : (int)$routeMatch->getParam('anrid'); + if ($anrId === 0 && $routeMatch->getMatchedRouteName() === 'monarc_api_duplicate_client_anr') { + /* Anr ID for the route 'client-duplicate-anr' is passed in the json body as "anr". */ + $anrId = (int)(json_decode((string)$request->getBody(), true, 512, JSON_THROW_ON_ERROR)['anr'] ?? 0); + } + + try { + /** @var Entity\Anr $anr */ + $anr = $this->anrTable->findById($anrId); + } catch (EntityNotFoundException) { + return $this->responseFactory->createResponse( + StatusCodeInterface::STATUS_NOT_FOUND, + sprintf('Analysis with ID "%s" was not found.', $anrId) + ); + } + + $result = $this->validateAnrStatusAndGetResponseIfInvalid($anr, $request, $routeMatch->getMatchedRouteName()); + if ($result !== null) { + return $result; + } + + /* Ensure the record in the anr is presented in the table, means at least read permissions are allowed. + * It's necessary e.g. for the "monarc_api_duplicate_client_anr" route. */ + $userAnr = $this->userAnrTable->findByAnrAndUser($anr, $this->connectedUser); + if (($userAnr === null && !$anr->isAnrSnapshot()) + /* There are no permissions set for snapshots, + so it's necessary to validate the referenced analysis has the access for the user at least to read. */ + || ($anr->isAnrSnapshot() + && ( + ($request->getMethod() !== Request::METHOD_GET + && !$this->isPostAuthorizedForRoute($routeMatch->getMatchedRouteName(), $request->getMethod()) + ) + || $this->userAnrTable + ->findByAnrAndUser($anr->getSnapshot()->getAnrReference(), $this->connectedUser) === null + ) + ) + ) { + return $this->responseFactory->createResponse( + StatusCodeInterface::STATUS_FORBIDDEN, + sprintf('Analysis with ID %s is not accessible for view.', $anrId) + ); + } + + /* A batch of routes has to be excluded from post (isPostAuthorizedForRoute) to bypass forbidden response. */ + if ($request->getMethod() !== Request::METHOD_GET + && !$userAnr->hasWriteAccess() + && !$this->isPostAuthorizedForRoute($routeMatch->getMatchedRouteName(), $request->getMethod()) + ) { + return $this->responseFactory->createResponse( + StatusCodeInterface::STATUS_FORBIDDEN, + sprintf('Analysis with ID %s is not accessible for any modifications.', $anrId) + ); + } + + $request = $request->withAttribute('anr', $anr); + + return $handler->handle($request); + } + + private function isRouteAndRequestExcludedFromValidation(RouteMatch $route, ServerRequestInterface $request): bool + { + /* The creation of anr or getList is called without anr ID, route "monarc_api_client_anr". */ + return $route->getMatchedRouteName() === 'monarc_api_client_anr' + && \in_array($request->getMethod(), [Request::METHOD_GET, Request::METHOD_POST], true) + && $route->getParam('id') === null; + } + + /** + * Even if user has view only permission to the analysis, it's allowed to perform export or generate deliverable. + */ + private function isPostAuthorizedForRoute(string $routeName, string $method) + { + return $method === Request::METHOD_POST + && ($routeName === 'monarc_api_global_client_anr/export' // export ANR + || $routeName === 'monarc_api_global_client_anr/instance_export' // export Instance + || $routeName === 'monarc_api_global_client_anr/objects_export' // export Object + || $routeName === 'monarc_api_global_client_anr/deliverable' // generate a report + ); + } + + /** + * Validates the anr status for NON GET method requests exclude DELETE (cancellation of background import). + * @throws \JsonException + */ + private function validateAnrStatusAndGetResponseIfInvalid( + Entity\Anr $anr, + ServerRequestInterface $request, + string $routeName + ): ?ResponseInterface { + /* GET requests are always allowed and cancellation of import (delete import process -> PID). */ + if ($request->getMethod() === Request::METHOD_GET + || ($request->getMethod() === Request::METHOD_DELETE + && $routeName === 'monarc_api_global_client_anr/instance_import' + ) + ) { + return null; + } + + if ($anr->isActive()) { + return null; + } + + /* Allow deleting anr if the status is waiting for import or there is an import error. */ + if ($routeName === 'monarc_api_client_anr' + && $request->getMethod() === Request::METHOD_DELETE + && ($anr->getStatus() === AnrSuperClass::STATUS_IMPORT_ERROR + || $anr->getStatus() === AnrSuperClass::STATUS_AWAITING_OF_IMPORT + ) + ) { + return null; + } + + /* Allow to restore a snapshot if there is an import error. */ + if ($routeName === 'monarc_api_global_client_anr/snapshot_restore' + && $anr->getStatus() === AnrSuperClass::STATUS_IMPORT_ERROR + && $request->getMethod() === Request::METHOD_POST + ) { + return null; + } + + $result = [ + 'status' => $anr->getStatusName(), + 'importStatus' => [], + ]; + + if ($anr->getStatus() === AnrSuperClass::STATUS_UNDER_IMPORT) { + $importCronTask = $this->cronTaskService->getLatestTaskByNameWithParam( + Entity\CronTask::NAME_INSTANCE_IMPORT, + ['anrId' => $anr->getId()] + ); + if ($importCronTask !== null && $importCronTask->getStatus() === Entity\CronTask::STATUS_IN_PROGRESS) { + $timeDiff = $importCronTask->getUpdatedAt() !== null + ? $importCronTask->getUpdatedAt()->diff(new DateTime()) + : $importCronTask->getCreatedAt()->diff(new DateTime()); + $instancesNumber = $this->instanceTable->countByAnrIdFromDate( + $anr->getId(), + $importCronTask->getUpdatedAt() ?? $importCronTask->getCreatedAt() + ); + $result['importStatus'] = [ + 'executionTime' => $timeDiff->h . ' hours ' . $timeDiff->i . ' min ' . $timeDiff->s . ' sec', + 'createdInstances' => $instancesNumber, + ]; + } + } elseif ($anr->getStatus() === AnrSuperClass::STATUS_IMPORT_ERROR) { + $importCronTask = $this->cronTaskService->getLatestTaskByNameWithParam( + Entity\CronTask::NAME_INSTANCE_IMPORT, + ['anrId' => $anr->getId()] + ); + if ($importCronTask !== null && $importCronTask->getStatus() === Entity\CronTask::STATUS_FAILURE) { + $result['importStatus'] = ['errorMessage' => $importCronTask->getResultMessage()]; + } + } + + return $this->responseFactory->createResponse( + StatusCodeInterface::STATUS_CONFLICT, + json_encode($result, JSON_THROW_ON_ERROR) + ); + } +} diff --git a/src/Model/Entity/Anr.php b/src/Model/Entity/Anr.php deleted file mode 100755 index d9b3c59e..00000000 --- a/src/Model/Entity/Anr.php +++ /dev/null @@ -1,207 +0,0 @@ -referentials = $referentials; - } - - /** - * @return Referential[] - */ - public function getReferentials() - { - return $this->referentials; - } - - public function setLanguage($language): self - { - $this->language = $language; - - return $this; - } - - public function getLanguage(): int - { - return $this->language; - } - - /** - * @ORM\PrePersist - */ - public function generateAndSetUuid(): self - { - $this->uuid = Uuid::uuid4(); - - return $this; - } - - public function getUuid(): string - { - return $this->uuid; - } - - public function setUuid(string $uuid): self - { - $this->uuid = $uuid; - - return $this; - } - - public function isVisibleOnDashboard(): bool - { - return (bool)$this->isVisibleOnDashboard; - } - - public function setIsVisibleOnDashboard(int $isVisibleOnDashboard): self - { - $this->isVisibleOnDashboard = $isVisibleOnDashboard; - - return $this; - } - - public function isStatsCollected(): bool - { - return (bool)$this->isStatsCollected; - } - - public function setIsStatsCollected(int $isStatsCollected): self - { - $this->isStatsCollected = $isStatsCollected; - - return $this; - } - - public function getLabel1(): string - { - return $this->label1; - } - - public function setLabel1(string $label): Anr - { - $this->label1 = $label; - - return $this; - } - - public function getLabel2(): string - { - return $this->label2; - } - - public function setLabel2(string $label): Anr - { - $this->label2 = $label; - - return $this; - } - - public function setLabel3(string $label): Anr - { - $this->label3 = $label; - - return $this; - } - - public function getLabel4(): string - { - return $this->label4; - } - - public function getLabel3(): string - { - return $this->label3; - } - - public function setLabel4(string $label): Anr - { - $this->label4 = $label; - - return $this; - } - - public function getModel(): ?int - { - return $this->model; - } -} diff --git a/src/Model/Entity/AnrMetadatasOnInstances.php b/src/Model/Entity/AnrMetadatasOnInstances.php deleted file mode 100644 index 305209c1..00000000 --- a/src/Model/Entity/AnrMetadatasOnInstances.php +++ /dev/null @@ -1,39 +0,0 @@ -isDeletable; - } - - public function setIsDeletable(bool $isDeletable): self - { - $this->isDeletable = (int)$isDeletable; - - return $this; - } -} diff --git a/src/Model/Entity/AnrObjectCategory.php b/src/Model/Entity/AnrObjectCategory.php deleted file mode 100755 index 8ea08be2..00000000 --- a/src/Model/Entity/AnrObjectCategory.php +++ /dev/null @@ -1,142 +0,0 @@ -id; - } - - /** - * @param int $id - */ - public function setId($id): self - { - $this->id = $id; - - return $this; - } - - /** - * @return Anr - */ - public function getAnr() - { - return $this->anr; - } - - /** - * @param AnrSuperClass $anr - */ - public function setAnr($anr): self - { - $this->anr = $anr; - - return $this; - } - - /** - * @return ObjectCategorySuperClass - */ - public function getCategory() - { - return $this->category; - } - - /** - * @param ObjectCategorySuperClass $category - * @return AnrObjectCategory - */ - public function setCategory($category) - { - $this->category = $category; - - return $this; - } - - public function setPosition(int $position): self - { - $this->position = $position; - - return $this; - } - - protected $parameters = [ - 'implicitPosition' => [ - 'field' => 'anr' - ] - ]; - - public function getInputFilter($partial = false) - { - if (!$this->inputFilter) { - parent::getInputFilter($partial); - } - return $this->inputFilter; - } -} diff --git a/src/Model/Entity/Client.php b/src/Model/Entity/Client.php deleted file mode 100755 index 4ded15d0..00000000 --- a/src/Model/Entity/Client.php +++ /dev/null @@ -1,149 +0,0 @@ -inputFilter) { - parent::getInputFilter($partial); - - $this->inputFilter->add([ - 'name' => 'name', - 'required' => ($partial) ? false : true, - 'filters' => [ - [ - 'name' => 'StringTrim', - ], - ], - 'validators' => [], - ]); - } - - return $this->inputFilter; - } - - public function getModels() - { - return $this->models; - } - - public function getId(): int - { - return $this->id; - } - - public function getName(): string - { - return (string)$this->name; - } - - public function setName(string $name): Client - { - $this->name = $name; - - return $this; - } - - public function getContactEmail(): string - { - return (string)$this->contactEmail; - } - - public function setContactEmail(string $contactEmail): Client - { - $this->contactEmail = $contactEmail; - - return $this; - } -} diff --git a/src/Model/Entity/Delivery.php b/src/Model/Entity/Delivery.php deleted file mode 100755 index ed3f437d..00000000 --- a/src/Model/Entity/Delivery.php +++ /dev/null @@ -1,120 +0,0 @@ -anr; - } - - /** - * @param Anr $anr - * @return Delivery - */ - public function setAnr($anr) - { - $this->anr = $anr; - return $this; - } -} diff --git a/src/Model/Entity/InstanceConsequence.php b/src/Model/Entity/InstanceConsequence.php deleted file mode 100755 index 596d037b..00000000 --- a/src/Model/Entity/InstanceConsequence.php +++ /dev/null @@ -1,46 +0,0 @@ -recommendationRisks; - } -} diff --git a/src/Model/Entity/InstanceRiskOp.php b/src/Model/Entity/InstanceRiskOp.php deleted file mode 100755 index 29c8528c..00000000 --- a/src/Model/Entity/InstanceRiskOp.php +++ /dev/null @@ -1,87 +0,0 @@ -recommendationRisks; - } -} diff --git a/src/Model/Entity/InstanceRiskOwner.php b/src/Model/Entity/InstanceRiskOwner.php deleted file mode 100644 index 644f012e..00000000 --- a/src/Model/Entity/InstanceRiskOwner.php +++ /dev/null @@ -1,23 +0,0 @@ -anr; - } - - /** - * @param Anr $anr - * @return Measure - */ - public function setAnr($anr) - { - $this->anr = $anr; - return $this; - } -} diff --git a/src/Model/Entity/MeasureMeasure.php b/src/Model/Entity/MeasureMeasure.php deleted file mode 100644 index 19a19c3d..00000000 --- a/src/Model/Entity/MeasureMeasure.php +++ /dev/null @@ -1,68 +0,0 @@ -anr; - } - - /** - * @param Anr $anr - */ - public function setAnr($anr): self - { - $this->anr = $anr; - - return $this; - } -} diff --git a/src/Model/Entity/MonarcObject.php b/src/Model/Entity/MonarcObject.php deleted file mode 100644 index c83c9864..00000000 --- a/src/Model/Entity/MonarcObject.php +++ /dev/null @@ -1,75 +0,0 @@ -anrs->contains($this->anr)) { - $this->anrs->add($this->anr); - } - - return $this; - } -} diff --git a/src/Model/Entity/ObjectCategory.php b/src/Model/Entity/ObjectCategory.php deleted file mode 100755 index 99bd2baa..00000000 --- a/src/Model/Entity/ObjectCategory.php +++ /dev/null @@ -1,21 +0,0 @@ -id; - } - - /** - * @param int $id - * @return Asset - */ - public function setId($id) - { - $this->id = $id; - return $this; - } - - /** - * @return Anr - */ - public function getAnr() - { - return $this->anr; - } - - /** - * @param Anr $anr - * @return Scale - */ - public function setAnr($anr) - { - $this->anr = $anr; - return $this; - } -} diff --git a/src/Model/Entity/RecommandationSet.php b/src/Model/Entity/RecommandationSet.php deleted file mode 100644 index 4e2943ce..00000000 --- a/src/Model/Entity/RecommandationSet.php +++ /dev/null @@ -1,207 +0,0 @@ -uuid; - } - - /** - * @param string $uuid - * @return self - */ - public function setUuid($uuid): self - { - $this->uuid = $uuid; - - return $this; - } - - /** - * @ORM\PrePersist - */ - public function generateAndSetUuid(): self - { - if ($this->uuid === null) { - $this->uuid = Uuid::uuid4(); - } - - return $this; - } - - /** - * @return Anr - */ - public function getAnr() - { - return $this->anr; - } - - /** - * @param Anr $anr - */ - public function setAnr($anr): self - { - $this->anr = $anr; - - return $this; - } - - /** - * @return Recommandation[] - */ - public function getRecommandations() - { - return $this->recommandations; - } - - /** - * @param Recommandation[] $recommandations - */ - public function setRecommandations($recommandations): self - { - $this->recommandations = $recommandations; - - return $this; - } - - public function setLabel1(string $label1): self - { - $this->label1 = $label1; - - return $this; - } - - public function setLabel2(string $label2): self - { - $this->label2 = $label2; - - return $this; - } - - public function setLabel3(string $label3): self - { - $this->label3 = $label3; - - return $this; - } - - public function setLabel4(string $label4): self - { - $this->label4 = $label4; - - return $this; - } - - public function getLabel(int $languageIndex): string - { - if (!\in_array($languageIndex, range(1, 4), true)) { - return ''; - } - - return (string)$this->{'label' . $languageIndex}; - } - - public function getInputFilter($partial = false) - { - if (!$this->inputFilter) { - parent::getInputFilter($partial); - - $texts = ['label1', 'label2', 'label3', 'label4']; - foreach ($texts as $text) { - $this->inputFilter->add(array( - 'name' => $text, - 'required' => strpos($text, (string)$this->getLanguage()) !== false && !$partial, - 'allow_empty' => false, - 'filters' => array(), - 'validators' => array(), - )); - } - } - - return $this->inputFilter; - } -} diff --git a/src/Model/Entity/RolfRisk.php b/src/Model/Entity/RolfRisk.php deleted file mode 100755 index 520a52de..00000000 --- a/src/Model/Entity/RolfRisk.php +++ /dev/null @@ -1,23 +0,0 @@ -id; - } - - public function getUser(): UserSuperClass - { - return $this->user; - } - - public function setUser(UserSuperClass $user): self - { - $this->user = $user; - - return $this; - } - - public function getAnr(): AnrSuperClass - { - return $this->anr; - } - - public function setAnr(AnrSuperClass $anr): self - { - $this->anr = $anr; - - return $this; - } - - public function getRwd(): int - { - return $this->rwd; - } - - public function setRwd(int $rwd): self - { - $this->rwd = $rwd; - - return $this; - } - - public function hasWriteAccess(): bool - { - return $this->rwd === 1; - } - - public function getInputFilter($partial = false) - { - if (!$this->inputFilter) { - parent::getInputFilter($partial); - - $this->inputFilter->add([ - 'name' => 'user', - 'required' => true, - 'allow_empty' => false, - 'filters' => [ - [ - 'name' => 'Digits', - ], - ], - ]); - - $this->inputFilter->add([ - 'name' => 'anr', - 'required' => true, - 'allow_empty' => false, - 'filters' => [ - [ - 'name' => 'Digits', - ], - ], - ]); - } - - return $this->inputFilter; - } -} diff --git a/src/Model/Entity/UserRole.php b/src/Model/Entity/UserRole.php deleted file mode 100644 index 3d5b52e7..00000000 --- a/src/Model/Entity/UserRole.php +++ /dev/null @@ -1,21 +0,0 @@ -getRepository()->createQueryBuilder('amv') - ->where('amv.anr = :anr') - ->andWhere('amv.uuid = :uuid') - ->setParameter('anr', $anr) - ->setParameter('uuid', $uuid) - ->getQuery() - ->getOneOrNullResult(); - } - - /** - * @return Amv[] - */ - public function findByAnr(Anr $anr): array - { - return $this->getRepository() - ->createQueryBuilder('amv') - ->where('amv.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - /** - * @return Amv[] - */ - public function findByAnrAndAsset(Anr $anr, Asset $asset): array - { - return $this->getRepository() - ->createQueryBuilder('amv') - ->innerJoin('amv.asset', 'a') - ->where('amv.anr = :anr') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('a.anr = :anr') - ->setParameter('anr', $anr) - ->setParameter('assetUuid', $asset->getUuid()) - ->getQuery() - ->getResult(); - } - - /** - * @throws EntityNotFoundException - */ - public function findByUuidAndAnrId(string $uuid, int $anrId): Amv - { - $amv = $this->getRepository() - ->createQueryBuilder('a') - ->select('a', 'm') - ->leftJoin('a.measures', 'm') - ->where('a.uuid = :uuid') - ->andWhere('a.anr = :anrId') - ->setParameter('uuid', $uuid) - ->setParameter('anrId', $anrId) - ->getQuery() - ->getOneOrNullResult(); - - if ($amv === null) { - throw new EntityNotFoundException( - sprintf('Amv with uuid "%s" and Anr id "%d" is not found', $uuid, $anrId) - ); - } - - return $amv; - } - - public function deleteEntity(AmvSuperClass $amv, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->remove($amv); - if ($flush) { - $em->flush(); - } - } - - public function saveEntity(AmvSuperClass $amv, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($amv); - if ($flushAll) { - $em->flush(); - } - } - - /** - * Called from Core/AmvService. - */ - public function findByAmvItemsUuidAndAnrId( - string $assetUuid, - string $threatUuid, - string $vulnerabilityUuid, - ?int $anrId = null - ): ?AmvSuperClass { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('amv') - ->innerJoin('amv.asset', 'a') - ->innerJoin('amv.threat', 't') - ->innerJoin('amv.vulnerability', 'v') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('t.uuid = :threatUuid') - ->andWhere('v.uuid = :vulnerabilityUuid') - ->setParameter('assetUuid', $assetUuid) - ->setParameter('threatUuid', $threatUuid) - ->setParameter('vulnerabilityUuid', $vulnerabilityUuid); - - if ($anrId !== null) { - $queryBuilder - ->andWhere('amv.anr = :anrId') - ->setParameter('anrId', $anrId) - ->andWhere('a.anr = :assetAnr') - ->andWhere('t.anr = :threatAnr') - ->andWhere('v.anr = :vulnerabilityAnr') - ->setParameter('assetAnr', $anrId) - ->setParameter('threatAnr', $anrId) - ->setParameter('vulnerabilityAnr', $anrId); - } - - return $queryBuilder - ->getQuery() - ->getOneOrNullResult(); - } - - /** - * TODO: the Core AmvTable has the same method, after #240 is done and the core table is inherited, can be removed. - * @return AmvSuperClass[] - */ - public function findByAsset(AssetSuperClass $asset) - { - return $this->getRepository() - ->createQueryBuilder('amv') - ->innerJoin('amv.asset', 'a') - ->where('amv.anr = :anr') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('a.anr = :assetAnr') - ->setParameter('anr', $asset->getAnr()) - ->setParameter('assetUuid', $asset->getUuid()) - ->setParameter('assetAnr', $asset->getAnr()) - ->getQuery() - ->getResult(); - } - - public function deleteEntities(array $entities): void - { - $this->getDb()->deleteAll($entities); - } -} diff --git a/src/Model/Table/AnrMetadatasOnInstancesTable.php b/src/Model/Table/AnrMetadatasOnInstancesTable.php deleted file mode 100644 index 5237e4c0..00000000 --- a/src/Model/Table/AnrMetadatasOnInstancesTable.php +++ /dev/null @@ -1,20 +0,0 @@ -getRepository() - ->createQueryBuilder('aoc') - ->select('MAX(aoc.position)') - ->where('aoc.anr = :anr') - ->setParameter('anr', $anr) - ->setMaxResults(1) - ->getQuery() - ->getSingleScalarResult(); - } - - public function saveEntity(AnrObjectCategory $anrObjectCategory, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($anrObjectCategory); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/AssetTable.php b/src/Model/Table/AssetTable.php deleted file mode 100755 index 331080e9..00000000 --- a/src/Model/Table/AssetTable.php +++ /dev/null @@ -1,71 +0,0 @@ -getRepository()->createQueryBuilder('a') - ->where('a.anr = :anr') - ->andWhere('a.uuid = :uuid') - ->setParameter('anr', $anr) - ->setParameter('uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - public function existsWithAnrAndCode(Anr $anr, string $code): bool - { - return $this->getRepository()->createQueryBuilder('a') - ->where('a.anr = :anr') - ->andWhere('a.uuid = :code') - ->setParameter('anr', $anr) - ->setParameter('code', $code) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult() !== null; - } - - /** - * @return Asset[] - */ - public function findByAnr(Anr $anr): array - { - return $this->getRepository()->createQueryBuilder('a') - ->where('a.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - public function saveEntity(Asset $asset, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($asset); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/ClientModelTable.php b/src/Model/Table/ClientModelTable.php deleted file mode 100644 index 61196182..00000000 --- a/src/Model/Table/ClientModelTable.php +++ /dev/null @@ -1,28 +0,0 @@ -getRepository()->findAll(); - } - - /** - * @throws EntityNotFoundException - */ - public function findById(int $id): Client - { - /** @var Client|null $client */ - $client = $this->getRepository()->find($id); - if ($client === null) { - throw EntityNotFoundException::fromClassNameAndIdentifier(\get_class($this), [$id]); - } - - return $client; - } - - public function saveEntity(Client $client, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($client); - if ($flushAll) { - $em->flush(); - } - } - - public function findTheClient(): Client - { - return $this->getRepository()->createQueryBuilder('client') - ->setMaxResults(1) - ->getQuery() - ->getSingleResult(); - } -} diff --git a/src/Model/Table/DeliveryTable.php b/src/Model/Table/DeliveryTable.php deleted file mode 100755 index 7d20a494..00000000 --- a/src/Model/Table/DeliveryTable.php +++ /dev/null @@ -1,25 +0,0 @@ -get('doctrine.entitymanager.orm_cli')); - } -} diff --git a/src/Model/Table/InstanceConsequenceTable.php b/src/Model/Table/InstanceConsequenceTable.php deleted file mode 100755 index 92ac5a2a..00000000 --- a/src/Model/Table/InstanceConsequenceTable.php +++ /dev/null @@ -1,72 +0,0 @@ -entityClass = InstanceConsequence::class; - } - - /** - * @param $anrId - * @return bool - */ - public function started($anrId) - { - $qb = $this->getRepository()->createQueryBuilder('t'); - $res = $qb->select('COUNT(t.id)') - ->innerJoin('t.instance', 'i') - ->where('t.anr = :anrid') - ->setParameter(':anrid', $anrId) - ->andWhere($qb->expr()->orX( - $qb->expr()->neq('t.c', -1), - $qb->expr()->neq('t.i', -1), - $qb->expr()->neq('t.d', -1), - $qb->expr()->neq('i.c', -1), - $qb->expr()->neq('i.i', -1), - $qb->expr()->neq('i.d', -1) - ))->getQuery()->getSingleScalarResult(); - - return $res > 0; - } - - /** - * @return InstanceConsequence[] - */ - public function findByAnrInstanceAndScaleImpactType( - Anr $anr, - Instance $instance, - ScaleImpactTypeSuperClass $scaleImpactType - ): array { - return $this->getRepository()->createQueryBuilder('ic') - ->where('ic.anr = :anr') - ->andWhere('ic.instance = :instance') - ->andWhere('ic.scaleImpactType = :scaleImpactType') - ->setParameter('anr', $anr) - ->setParameter('instance', $instance) - ->setParameter('scaleImpactType', $scaleImpactType) - ->getQuery() - ->getResult(); - } -} diff --git a/src/Model/Table/InstanceMetadataTable.php b/src/Model/Table/InstanceMetadataTable.php deleted file mode 100644 index 052d71a3..00000000 --- a/src/Model/Table/InstanceMetadataTable.php +++ /dev/null @@ -1,50 +0,0 @@ -getRepository()->createQueryBuilder('im') - ->where('im.instance = :instance') - ->setParameter('instance', $instance) - ->getQuery() - ->getResult(); - } - - /** - * @return InstanceMetadata¦null - */ - public function findByInstanceAndMetadata( - Instance $instance, - AnrMetadatasOnInstancesSuperClass $metadata - ):?InstanceMetadata { - return $this->getRepository()->createQueryBuilder('im') - ->where('im.instance = :instance') - ->andWhere('im.metadata = :metadata') - ->setParameter('instance', $instance) - ->setParameter('metadata', $metadata) - ->getQuery() - ->getOneOrNullResult(); - } -} diff --git a/src/Model/Table/InstanceRiskOwnerTable.php b/src/Model/Table/InstanceRiskOwnerTable.php deleted file mode 100644 index 7ad72dcc..00000000 --- a/src/Model/Table/InstanceRiskOwnerTable.php +++ /dev/null @@ -1,20 +0,0 @@ -getRepository()->createQueryBuilder('t'); - $res = $qb->select('COUNT(t.id)') - ->where('t.anr = :anrid') - ->setParameter(':anrid', $anrId) - ->andWhere($qb->expr()->orX( - $qb->expr()->neq('t.threatRate', -1), - $qb->expr()->neq('t.vulnerabilityRate', -1) - ))->getQuery()->getSingleScalarResult(); - - return $res > 0; - } - - /** - * @return InstanceRisk[] - */ - public function findByInstanceAndInstanceRiskRelations( - InstanceSuperClass $instance, - InstanceRiskSuperClass $instanceRisk, - bool $excludeAmvFilter = false, - bool $includeAssetFilter = false - ) { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('ir') - ->where('ir.instance = :instance') - ->setParameter('instance', $instance); - - if (!$excludeAmvFilter && $instanceRisk->getAmv() !== null) { - $queryBuilder - ->innerJoin('ir.amv', 'amv') - ->andWhere('amv.uuid = :amvUuid') - ->andWhere('amv.anr = :amvAnr') - ->setParameter('amvUuid', $instanceRisk->getAmv()->getUuid()) - ->setParameter('amvAnr', $instanceRisk->getAmv()->getAnr()); - } - if ($includeAssetFilter) { - $queryBuilder - ->innerJoin('ir.asset', 'a') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('a.anr = :assetAnr') - ->setParameter('assetUuid', $instanceRisk->getAsset()->getUuid()) - ->setParameter('assetAnr', $instanceRisk->getAsset()->getAnr()); - } - - $queryBuilder - ->innerJoin('ir.threat', 'thr') - ->innerJoin('ir.vulnerability', 'vuln') - ->andWhere('thr.uuid = :threatUuid') - ->andWhere('thr.anr = :threatAnr') - ->andWhere('vuln.uuid = :vulnerabilityUuid') - ->andWhere('vuln.anr = :vulnerabilityAnr') - ->setParameter('threatUuid', $instanceRisk->getThreat()->getUuid()) - ->setParameter('threatAnr', $instanceRisk->getThreat()->getAnr()) - ->setParameter('vulnerabilityUuid', $instanceRisk->getVulnerability()->getUuid()) - ->setParameter('vulnerabilityAnr', $instanceRisk->getVulnerability()->getAnr()); - - if ($instanceRisk->isSpecific()) { - $queryBuilder->andWhere('ir.specific = ' . InstanceRiskSuperClass::TYPE_SPECIFIC); - } - - return $queryBuilder->getQuery()->getResult(); - } - - public function findByInstanceAssetThreatUuidAndVulnerabilityUuid( - InstanceSuperClass $instance, - AssetSuperClass $asset, - string $threatUuid, - string $vulnerabilityUuid - ): ?InstanceRisk { - return $this->getRepository() - ->createQueryBuilder('ir') - ->innerJoin('ir.asset', 'a') - ->innerJoin('ir.threat', 'thr') - ->innerJoin('ir.vulnerability', 'vuln') - ->where('ir.instance = :instance') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('a.anr = :assetAnr') - ->andWhere('thr.uuid = :threatUuid') - ->andWhere('thr.anr = :threatAnr') - ->andWhere('vuln.uuid = :vulnerabilityUuid') - ->andWhere('vuln.anr = :vulnerabilityAnr') - ->setParameter('instance', $instance) - ->setParameter('assetUuid', $asset->getUuid()) - ->setParameter('assetAnr', $asset->getAnr()) - ->setParameter('threatUuid', $threatUuid) - ->setParameter('threatAnr', $instance->getAnr()) - ->setParameter('vulnerabilityUuid', $vulnerabilityUuid) - ->setParameter('vulnerabilityAnr', $instance->getAnr()) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - /** - * @return InstanceRisk[] - */ - public function findByAmv(AmvSuperClass $amv) - { - return $this->getRepository() - ->createQueryBuilder('ir') - ->innerJoin('ir.amv', 'amv') - ->where('amv.uuid = :amvUuid') - ->andWhere('amv.anr = :amvAnr') - ->setParameter('amvUuid', $amv->getUuid()) - ->setParameter('amvAnr', $amv->getAnr()) - ->getQuery() - ->getResult(); - } - - /** - * @return InstanceRisk[] - */ - public function findByInstanceAndAmv(InstanceSuperClass $instance, AmvSuperClass $amv) - { - return $this->getRepository() - ->createQueryBuilder('ir') - ->innerJoin('ir.amv', 'amv') - ->where('ir.instance = :instance') - ->andWhere('amv.uuid = :amvUuid') - ->andWhere('amv.anr = :amvAnr') - ->setParameter('instance', $instance) - ->setParameter('amvUuid', $amv->getUuid()) - ->setParameter('amvAnr', $amv->getAnr()) - ->getQuery() - ->getResult(); - } - - public function findRisksDataForStatsByAnr(Anr $anr): array - { - return $this->getRepository() - ->createQueryBuilder('ir') - ->select(' - ir.id, - IDENTITY(ir.asset) as assetId, - t.uuid as threatId, - v.uuid as vulnerabilityId, - ir.cacheMaxRisk, - ir.cacheTargetedRisk, - ir.threatRate, - ir.vulnerabilityRate, - i.c as instanceConfidentiality, - i.i as instanceIntegrity, - i.d as instanceAvailability, - t.c as threatConfidentiality, - t.i as threatIntegrity, - t.a as threatAvailability, - t.label1 as threatLabel1, - t.label2 as threatLabel2, - t.label3 as threatLabel3, - t.label4 as threatLabel4, - v.label1 as vulnerabilityLabel1, - v.label2 as vulnerabilityLabel2, - v.label3 as vulnerabilityLabel3, - v.label4 as vulnerabilityLabel4, - o.scope, - o.uuid as objectId - ') - ->where('ir.anr = :anr') - ->setParameter(':anr', $anr) - ->andWhere('ir.cacheMaxRisk > -1 OR ir.cacheTargetedRisk > -1') - ->innerJoin('ir.instance', 'i') - ->innerJoin('ir.threat', 't') - ->innerJoin('ir.vulnerability', 'v') - ->innerJoin('i.object', 'o') - ->getQuery() - ->getResult(); - } -} diff --git a/src/Model/Table/InterviewTable.php b/src/Model/Table/InterviewTable.php index dccfcc06..ae13d39d 100755 --- a/src/Model/Table/InterviewTable.php +++ b/src/Model/Table/InterviewTable.php @@ -7,10 +7,11 @@ namespace Monarc\FrontOffice\Model\Table; +use Monarc\FrontOffice\Entity\Anr; use Monarc\FrontOffice\Model\DbCli; use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; -use Monarc\FrontOffice\Model\Entity\Interview; +use Monarc\FrontOffice\Entity\Interview; /** * Class InterviewTable @@ -22,4 +23,26 @@ public function __construct(DbCli $dbService, ConnectedUserService $connectedUse { parent::__construct($dbService, Interview::class, $connectedUserService); } + + public function saveEntity(Interview $interview, bool $flushAll = true): void + { + $em = $this->getDb()->getEntityManager(); + $em->persist($interview); + if ($flushAll) { + $em->flush(); + } + } + + /** + * @return Interview[] + */ + public function findByAnr(Anr $anr): array + { + return $this->getRepository() + ->createQueryBuilder('i') + ->where('i.anr = :anr') + ->setParameter('anr', $anr) + ->getQuery() + ->getResult(); + } } diff --git a/src/Model/Table/MeasureMeasureTable.php b/src/Model/Table/MeasureMeasureTable.php deleted file mode 100644 index 6e3a6cdd..00000000 --- a/src/Model/Table/MeasureMeasureTable.php +++ /dev/null @@ -1,48 +0,0 @@ -getRepository()->createQueryBuilder('mm') - ->where('mm.anr = :anr') - ->andWhere('mm.father = :father') - ->andWhere('mm.child = :child') - ->setParameter('anr', $anr) - ->setParameter('father', $fatherUuid) - ->setParameter('child', $childUuid) - ->getQuery() - ->getOneOrNullResult(); - } - - public function saveEntity(MeasureMeasure $measureMeasure, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($measureMeasure); - if ($flush) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/MeasureTable.php b/src/Model/Table/MeasureTable.php deleted file mode 100755 index 78dc03f3..00000000 --- a/src/Model/Table/MeasureTable.php +++ /dev/null @@ -1,55 +0,0 @@ -entityClass = Measure::class; - } - - /** - * @return Measure[] - */ - public function findByAnr(Anr $anr): array - { - return $this->getRepository() - ->createQueryBuilder('m') - ->where('m.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - public function findByAnrAndUuid(AnrSuperClass $anr, string $uuid): ?Measure - { - return $this->getRepository() - ->createQueryBuilder('m') - ->where('m.anr = :anr') - ->setParameter('anr', $anr) - ->andWhere('m.uuid = :uuid') - ->setParameter('uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } -} diff --git a/src/Model/Table/MonarcObjectTable.php b/src/Model/Table/MonarcObjectTable.php deleted file mode 100755 index f598dc77..00000000 --- a/src/Model/Table/MonarcObjectTable.php +++ /dev/null @@ -1,123 +0,0 @@ -getRepository() - ->createQueryBuilder('mo') - ->where('mo.anr = :anr') - ->andWhere('mo.uuid = :uuid') - ->setParameter('anr', $anr) - ->setParameter('uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - - if ($monarcObject === null) { - throw EntityNotFoundException::fromClassNameAndIdentifier(\get_class($this), [$anr->getId(), $uuid]); - } - - return $monarcObject; - } - - public function findOneByAnrAssetNameScopeAndCategory( - AnrSuperClass $anr, - string $nameKey, - string $nameValue, - AssetSuperClass $asset, - int $scope, - ObjectCategorySuperClass $category - ): ?MonarcObject { - return $this->getRepository() - ->createQueryBuilder('mo') - ->innerJoin('mo.asset', 'a') - ->where('mo.anr = :anr') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('a.anr = :assetAnr') - ->andWhere('mo.' . $nameKey . ' = :name') - ->andWhere('mo.scope = :scope') - ->andWhere('mo.category = :category') - ->setParameter('anr', $anr) - ->setParameter('assetUuid', $asset->getUuid()) - ->setParameter('assetAnr', $anr) - ->setParameter('name', $nameValue) - ->setParameter('scope', $scope) - ->setParameter('category', $category) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - public function findOneByAnrCategoryAndName( - AnrSuperClass $anr, - ?ObjectCategory $objectCategory, - string $nameKey, - string $nameValue - ): ?MonarcObject { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('mo') - ->where('mo.anr = :anr') - ->andWhere('mo.' . $nameKey . ' = :name') - ->setParameter('anr', $anr) - ->setParameter('name', $nameValue) - ->setMaxResults(1); - if ($objectCategory === null) { - $queryBuilder->andWhere('mo.category IS NULL'); - } else { - $queryBuilder->andWhere('mo.category = :category') - ->setParameter('category', $objectCategory); - } - - return $queryBuilder->getQuery()->getOneOrNullResult(); - } - - /** - * @return ObjectSuperClass[] - */ - public function findByAnrAndRolfTag(AnrSuperClass $anr, RolfTagSuperClass $rolfTag): array - { - return $this->getRepository() - ->createQueryBuilder('o') - ->where('o.anr = :anr') - ->setParameter('anr', $anr) - ->andWhere('o.rolfTag = :rolfTag') - ->setParameter('rolfTag', $rolfTag) - ->getQuery() - ->getResult(); - } -} diff --git a/src/Model/Table/ObjectObjectTable.php b/src/Model/Table/ObjectObjectTable.php deleted file mode 100755 index 50def104..00000000 --- a/src/Model/Table/ObjectObjectTable.php +++ /dev/null @@ -1,102 +0,0 @@ -getRepository()->createQueryBuilder('oo') - ->innerJoin('oo.father', 'father') - ->where('father.uuid = :fatherUuuid') - ->andWhere('father.anr = :fatherAnr') - ->setParameter('fatherUuuid', $monarcObject->getUuid()) - ->setParameter('fatherAnr', $monarcObject->getAnr()) - ->getQuery() - ->getResult(); - - if (!empty($childrenObjects)) { - foreach ($childrenObjects as $childObject) { - $this->getDb()->getEntityManager()->remove($childObject); - } - $this->getDb()->flush(); - } - } - - public function findMaxPositionByAnrAndFather(Anr $anr, MonarcObject $father): int - { - return (int)$this->getRepository()->createQueryBuilder('oo') - ->select('MAX(oo.position)') - ->innerJoin('oo.father', 'father') - ->where('oo.anr = :anr') - ->andWhere('father.uuid = :fatherUuid') - ->andWhere('father.anr = :fatherAnr') - ->setParameter('anr', $anr) - ->setParameter('fatherUuid', $father->getUuid()) - ->setParameter('fatherAnr', $anr) - ->getQuery() - ->getSingleScalarResult(); - } - - /** - * @return ObjectObject[] - */ - public function findChildrenByFather(MonarcObject $father, array $order = []): array - { - $queryBuilder = $this->getRepository()->createQueryBuilder('oo') - ->innerJoin('oo.father', 'father') - ->where('father.uuid = :fatherUuid') - ->andWhere('father.anr = :fatherAnr') - ->setParameter('fatherUuid', $father->getUuid()) - ->setParameter('fatherAnr', $father->getAnr()); - - if (!empty($order)) { - foreach ($order as $field => $direction) { - $queryBuilder->orderBy('oo.' . $field, $direction); - } - } - - return $queryBuilder->getQuery()->getResult(); - } - - public function saveEntity(ObjectObjectSuperClass $objectObject, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($objectObject); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/PasswordTokenTable.php b/src/Model/Table/PasswordTokenTable.php deleted file mode 100755 index 69c09abc..00000000 --- a/src/Model/Table/PasswordTokenTable.php +++ /dev/null @@ -1,23 +0,0 @@ -getDb()->getEntityManager(); + $em->persist($question); + if ($flushAll) { + $em->flush(); + } + } } diff --git a/src/Model/Table/QuestionTable.php b/src/Model/Table/QuestionTable.php index 796d1008..2ad25d86 100755 --- a/src/Model/Table/QuestionTable.php +++ b/src/Model/Table/QuestionTable.php @@ -10,7 +10,8 @@ use Monarc\FrontOffice\Model\DbCli; use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; -use Monarc\FrontOffice\Model\Entity\Question; +use Monarc\FrontOffice\Entity\Anr; +use Monarc\FrontOffice\Entity\Question; /** * Class QuestionTable @@ -22,4 +23,35 @@ public function __construct(DbCli $dbService, ConnectedUserService $connectedUse { parent::__construct($dbService, Question::class, $connectedUserService); } + + /** + * @return Question[] + */ + public function findByAnr(Anr $anr): array + { + return $this->getRepository() + ->createQueryBuilder('q') + ->where('q.anr = :anr') + ->setParameter('anr', $anr) + ->getQuery() + ->getResult(); + } + + public function saveEntity(Question $question, bool $flushAll = true): void + { + $em = $this->getDb()->getEntityManager(); + $em->persist($question); + if ($flushAll) { + $em->flush(); + } + } + + public function deleteEntity(Question $question, bool $flush = true): void + { + $em = $this->getDb()->getEntityManager(); + $em->remove($question); + if ($flush) { + $em->flush(); + } + } } diff --git a/src/Model/Table/RecommandationSetTable.php b/src/Model/Table/RecommandationSetTable.php deleted file mode 100644 index 4e758413..00000000 --- a/src/Model/Table/RecommandationSetTable.php +++ /dev/null @@ -1,94 +0,0 @@ -getRepository() - ->createQueryBuilder('rs') - ->where('rs.anr = :anr') - ->andWhere('rs.uuid = :uuid') - ->setParameter('anr', $anr) - ->setParameter('uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - - if ($recommendationSet === null) { - throw new EntityNotFoundException( - sprintf('Recommendation set with anr ID "%d" and uuid "%s" has not been found.', $anr->getId(), $uuid) - ); - } - - return $recommendationSet; - } - - /** - * @return RecommandationSet[] - */ - public function findByAnr(Anr $anr): array - { - return $this->getRepository() - ->createQueryBuilder('rs') - ->where('rs.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - /** - * @throws ORMException - * @throws OptimisticLockException - */ - public function deleteEntity(RecommandationSet $recommendationSet, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->remove($recommendationSet); - if ($flush) { - $em->flush(); - } - } - - /** - * @throws ORMException - * @throws OptimisticLockException - */ - public function saveEntity(RecommandationSet $recommendationSet, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($recommendationSet); - if ($flush) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/RecommendationHistoricTable.php b/src/Model/Table/RecommendationHistoricTable.php deleted file mode 100755 index 5672c0b2..00000000 --- a/src/Model/Table/RecommendationHistoricTable.php +++ /dev/null @@ -1,35 +0,0 @@ -getRepository() - ->createQueryBuilder('rh') - ->where('rh.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } -} diff --git a/src/Model/Table/RecordActorTable.php b/src/Model/Table/RecordActorTable.php index 8dbdc576..cc306535 100644 --- a/src/Model/Table/RecordActorTable.php +++ b/src/Model/Table/RecordActorTable.php @@ -10,7 +10,7 @@ use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\RecordActor; +use Monarc\FrontOffice\Entity\RecordActor; /** * Class RecordActorTable diff --git a/src/Model/Table/RecordDataCategoryTable.php b/src/Model/Table/RecordDataCategoryTable.php index 249d2783..fb17d017 100644 --- a/src/Model/Table/RecordDataCategoryTable.php +++ b/src/Model/Table/RecordDataCategoryTable.php @@ -10,7 +10,7 @@ use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\RecordDataCategory; +use Monarc\FrontOffice\Entity\RecordDataCategory; /** * Class RecordDataCategoryTable diff --git a/src/Model/Table/RecordInternationalTransferTable.php b/src/Model/Table/RecordInternationalTransferTable.php index 6e959431..e7fcf8e5 100644 --- a/src/Model/Table/RecordInternationalTransferTable.php +++ b/src/Model/Table/RecordInternationalTransferTable.php @@ -10,7 +10,7 @@ use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\RecordInternationalTransfer; +use Monarc\FrontOffice\Entity\RecordInternationalTransfer; /** * Class RecordInternationalTransferTable diff --git a/src/Model/Table/RecordPersonalDataTable.php b/src/Model/Table/RecordPersonalDataTable.php index cd5d9bb2..842b86e1 100644 --- a/src/Model/Table/RecordPersonalDataTable.php +++ b/src/Model/Table/RecordPersonalDataTable.php @@ -10,7 +10,7 @@ use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\RecordPersonalData; +use Monarc\FrontOffice\Entity\RecordPersonalData; /** * Class RecordPersonalDataTable diff --git a/src/Model/Table/RecordProcessorTable.php b/src/Model/Table/RecordProcessorTable.php index d8b1830d..33f447d7 100644 --- a/src/Model/Table/RecordProcessorTable.php +++ b/src/Model/Table/RecordProcessorTable.php @@ -10,7 +10,7 @@ use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\RecordProcessor; +use Monarc\FrontOffice\Entity\RecordProcessor; /** * Class RecordProcessorTable diff --git a/src/Model/Table/RecordRecipientTable.php b/src/Model/Table/RecordRecipientTable.php index 06050ffe..2fe90be0 100644 --- a/src/Model/Table/RecordRecipientTable.php +++ b/src/Model/Table/RecordRecipientTable.php @@ -10,7 +10,7 @@ use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\RecordRecipient; +use Monarc\FrontOffice\Entity\RecordRecipient; /** * Class RecordRecipientTable diff --git a/src/Model/Table/RecordTable.php b/src/Model/Table/RecordTable.php index 1fdc86ae..39cca0f0 100644 --- a/src/Model/Table/RecordTable.php +++ b/src/Model/Table/RecordTable.php @@ -7,19 +7,40 @@ namespace Monarc\FrontOffice\Model\Table; +use Doctrine\ORM\EntityNotFoundException; use Monarc\Core\Model\Table\AbstractEntityTable; use Monarc\Core\Service\ConnectedUserService; +use Monarc\FrontOffice\Entity\Anr; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Entity\Record; +use Monarc\FrontOffice\Entity\Record; -/** - * Class RecordTable - * @package Monarc\FrontOffice\Model\Table - */ class RecordTable extends AbstractEntityTable { public function __construct(DbCli $dbService, ConnectedUserService $connectedUserService) { parent::__construct($dbService, Record::class, $connectedUserService); } + + public function findById(int $id): Record + { + $record = $this->getRepository()->find($id); + if ($record === null) { + throw EntityNotFoundException::fromClassNameAndIdentifier(\get_class($this), [$id]); + } + + return $record; + } + + /** + * @return Record[] + */ + public function findByAnr(Anr $anr): array + { + return $this->getRepository() + ->createQueryBuilder('r') + ->where('r.anr = :anr') + ->setParameter('anr', $anr) + ->getQuery() + ->getResult(); + } } diff --git a/src/Model/Table/ReferentialTable.php b/src/Model/Table/ReferentialTable.php deleted file mode 100644 index b5d2d794..00000000 --- a/src/Model/Table/ReferentialTable.php +++ /dev/null @@ -1,66 +0,0 @@ -getRepository() - ->createQueryBuilder('r') - ->where('r.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - /** - * @return Referential|null - * @throws NonUniqueResultException - */ - public function findByAnrAndUuid(Anr $anr, string $uuid): ?Referential - { - return $this->getRepository() - ->createQueryBuilder('r') - ->where('r.anr = :anr') - ->andWhere('r.uuid = :uuid') - ->setParameter('anr', $anr) - ->setParameter('uuid', $uuid) - ->getQuery() - ->getOneOrNullResult(); - } - - public function saveEntity(ReferentialSuperClass $referential, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($referential); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/RolfRiskTable.php b/src/Model/Table/RolfRiskTable.php deleted file mode 100755 index 1951824d..00000000 --- a/src/Model/Table/RolfRiskTable.php +++ /dev/null @@ -1,41 +0,0 @@ -entityClass = RolfRisk::class; - } - - public function findByAnrAndCode(Anr $anr, string $code): ?RolfRisk - { - return $this->getRepository() - ->createQueryBuilder('rr') - ->where('rr.anr = :anr') - ->andWhere('rr.code = :code') - ->setParameter('anr', $anr) - ->setParameter('code', $code) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } -} diff --git a/src/Model/Table/RolfTagTable.php b/src/Model/Table/RolfTagTable.php deleted file mode 100755 index 6789d171..00000000 --- a/src/Model/Table/RolfTagTable.php +++ /dev/null @@ -1,50 +0,0 @@ -entityClass = RolfTag::class; - } - - public function findByAnrAndCode(Anr $anr, string $code): ?RolfTag - { - return $this->getRepository() - ->createQueryBuilder('rt') - ->where('rt.anr = :anr') - ->setParameter('anr', $anr) - ->andWhere('rt.code = :code') - ->setParameter('code', $code) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - public function saveEntity(RolfTag $rolfTag, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($rolfTag); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/ScaleCommentTable.php b/src/Model/Table/ScaleCommentTable.php deleted file mode 100755 index 6cc971ce..00000000 --- a/src/Model/Table/ScaleCommentTable.php +++ /dev/null @@ -1,27 +0,0 @@ -entityClass = ScaleComment::class; - } -} diff --git a/src/Model/Table/ScaleImpactTypeTable.php b/src/Model/Table/ScaleImpactTypeTable.php deleted file mode 100755 index e8d9f73d..00000000 --- a/src/Model/Table/ScaleImpactTypeTable.php +++ /dev/null @@ -1,92 +0,0 @@ -getRepository() - ->createQueryBuilder('sit') - ->where('sit.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - /** - * @return ScaleImpactType[] - */ - public function findByAnrOrderedByPosition(Anr $anr): array - { - return $this->getRepository() - ->createQueryBuilder('sit') - ->where('sit.anr = :anr') - ->setParameter('anr', $anr) - ->addOrderBy('sit.position') - ->getQuery() - ->getResult(); - } - - /** - * @return ScaleImpactType[] - */ - public function findByAnrOrderedAndIndexedByPosition(Anr $anr): array - { - return $this->getRepository() - ->createQueryBuilder('sit', 'sit.position') - ->where('sit.anr = :anr') - ->setParameter('anr', $anr) - ->addOrderBy('sit.position') - ->getQuery() - ->getResult(); - } - - public function findMaxPositionByAnrAndScale(Anr $anr, Scale $scale): int - { - return (int)$this->getRepository() - ->createQueryBuilder('sit') - ->select('MAX(sit.position)') - ->where('sit.anr = :anr') - ->andWhere('sit.scale = :scale') - ->setParameter('anr', $anr) - ->setParameter('scale', $scale) - ->setMaxResults(1) - ->getQuery() - ->getSingleScalarResult(); - } - - public function saveEntity(ScaleImpactTypeSuperClass $scaleImpactType, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($scaleImpactType); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/ScaleTable.php b/src/Model/Table/ScaleTable.php deleted file mode 100755 index d66803b3..00000000 --- a/src/Model/Table/ScaleTable.php +++ /dev/null @@ -1,50 +0,0 @@ -entityClass = Scale::class; - } - - public function findByAnrAndType(AnrSuperClass $anr, int $type): Scale - { - $scale = $this->getRepository() - ->createQueryBuilder('s') - ->where('s.anr = :anr') - ->andWhere('s.type = :type') - ->setParameter('anr', $anr) - ->setParameter('type', $type) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - - if ($scale === null) { - throw new EntityNotFoundException( - sprintf('Scale of type "%d" doesn\'t exist in anr ID: "%d"', $type, $anr->getId()) - ); - } - - return $scale; - } -} diff --git a/src/Model/Table/SnapshotTable.php b/src/Model/Table/SnapshotTable.php deleted file mode 100755 index eeedbf73..00000000 --- a/src/Model/Table/SnapshotTable.php +++ /dev/null @@ -1,61 +0,0 @@ -getDb()->getEntityManager(); - $em->persist($snapshot); - if ($flushAll) { - $em->flush(); - } - } - - /** - * @throws EntityNotFoundException - */ - public function findById(int $id): Snapshot - { - /** @var Snapshot|null $snapshot */ - $snapshot = $this->getRepository()->find($id); - if ($snapshot === null) { - throw new EntityNotFoundException(sprintf('Snapshot with id "%d" was not found', $id)); - } - - return $snapshot; - } - - /** - * @return Snapshot[]|array - */ - public function findAll(): array - { - return $this->getRepository()->findAll(); - } -} diff --git a/src/Model/Table/SoaCategoryTable.php b/src/Model/Table/SoaCategoryTable.php deleted file mode 100755 index 2087d8ba..00000000 --- a/src/Model/Table/SoaCategoryTable.php +++ /dev/null @@ -1,51 +0,0 @@ -getRepository()->createQueryBuilder('sc') - ->select('sc', 'ref') - ->innerJoin('sc.referential', 'ref') - ->where('sc.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - public function saveEntity(SoaCategorySuperClass $soaCategory, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($soaCategory); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/SoaTable.php b/src/Model/Table/SoaTable.php deleted file mode 100755 index 216a6342..00000000 --- a/src/Model/Table/SoaTable.php +++ /dev/null @@ -1,100 +0,0 @@ -getRepository() - ->createQueryBuilder('s') - ->where('s.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - public function saveEntity(Soa $soa, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($soa); - if ($flushAll) { - $em->flush(); - } - } - - /** - * @return Soa[] - */ - public function findByAnrAndSoaCategory(Anr $anr, SoaCategory $soaCategory, array $order = []) - { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('s') - ->innerJoin('s.measure', 'm') - ->where('s.anr = :anr') - ->andWhere('m.category = :category') - ->setParameter('anr', $anr) - ->setParameter('category', $soaCategory); - - if (!empty($order)) { - foreach ($order as $filed => $direction) { - $queryBuilder->addOrderBy($filed, $direction); - } - } - - return $queryBuilder->getQuery()->getResult(); - } - - - public function findByAnrAndMeasureUuid(Anr $anr, string $measureUuid): ?Soa - { - return $this->getRepository() - ->createQueryBuilder('s') - ->innerJoin('s.measure', 'm') - ->where('s.anr = :anr') - ->andWhere('m.uuid = :measure_uuid') - ->andWhere('m.anr = :anr') - ->setParameter('anr', $anr) - ->setParameter('measure_uuid', $measureUuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - public function findById(int $id): ?Soa - { - return $this->getRepository() - ->createQueryBuilder('s') - ->where('s.id = :id') - ->setParameter('id', $id) - ->getQuery() - ->getOneOrNullResult(); - } -} diff --git a/src/Model/Table/ThemeTable.php b/src/Model/Table/ThemeTable.php deleted file mode 100755 index 3f2d0649..00000000 --- a/src/Model/Table/ThemeTable.php +++ /dev/null @@ -1,48 +0,0 @@ -getRepository()->find($id); - } - - /** - * @return Theme[] - */ - public function findByAnr(Anr $anr): array - { - return $this->getRepository()->createQueryBuilder('t') - ->where('t.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } -} diff --git a/src/Model/Table/ThreatTable.php b/src/Model/Table/ThreatTable.php deleted file mode 100755 index 01a10d81..00000000 --- a/src/Model/Table/ThreatTable.php +++ /dev/null @@ -1,91 +0,0 @@ -getRepository()->createQueryBuilder('t'); - $res = $qb->select('COUNT(t.uuid)') - ->where('t.anr = :anrid') - ->setParameter(':anrid', $anrId) - ->andWhere('t.qualification != -1') - ->getQuery() - ->getSingleScalarResult(); - - return $res > 0; - } - - /** - * @return Threat[] - */ - public function findByAnr(Anr $anr) - { - return $this->getRepository() - ->createQueryBuilder('t') - ->where('t.anr = :anr') - ->setParameter(':anr', $anr) - ->getQuery() - ->getResult(); - } - - public function findByAnrAndUuid(Anr $anr, string $uuid): ?Threat - { - return $this->getRepository() - ->createQueryBuilder('t') - ->where('t.anr = :anr') - ->andWhere('t.uuid = :uuid') - ->setParameter(':anr', $anr) - ->setParameter(':uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - public function existsWithAnrAndCode(Anr $anr, string $code): bool - { - return $this->getRepository()->createQueryBuilder('t') - ->where('t.anr = :anr') - ->andWhere('t.code = :code') - ->setParameter('anr', $anr) - ->setParameter('code', $code) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult() !== null; - } - - public function saveEntity(ThreatSuperClass $threat, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($threat); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/UserAnrTable.php b/src/Model/Table/UserAnrTable.php deleted file mode 100755 index 14e6ef25..00000000 --- a/src/Model/Table/UserAnrTable.php +++ /dev/null @@ -1,62 +0,0 @@ -getRepository() - ->createQueryBuilder('ua') - ->where('ua.anr = :anr') - ->andWhere('ua.user = :user') - ->setParameter('anr', $anr) - ->setParameter('user', $user) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - } - - /** - * @return UserAnr[] - */ - public function findByAnrId(int $anrId) - { - return $this->getRepository() - ->createQueryBuilder('ua') - ->where('ua.anr = :anrId') - ->setParameter('anrId', $anrId) - ->getQuery() - ->getResult(); - } - - public function saveEntity(UserAnr $userAnr, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($userAnr); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Model/Table/UserTable.php b/src/Model/Table/UserTable.php deleted file mode 100755 index 83df48c7..00000000 --- a/src/Model/Table/UserTable.php +++ /dev/null @@ -1,45 +0,0 @@ -getRepository() - ->createQueryBuilder('v') - ->where('v.anr = :anr') - ->andWhere('v.uuid = :uuid') - ->setParameter(':anr', $anr) - ->setParameter(':uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - - if ($errorIfNotFound && $vulnerability === null) { - throw new EntityNotFoundException( - sprintf('Vulnerability with anr ID "%d" and uuid "%s" has not been found.', $anr->getId(), $uuid) - ); - } - - return $vulnerability; - } - - public function existsWithAnrAndCode(Anr $anr, string $code): bool - { - return $this->getRepository()->createQueryBuilder('v') - ->where('v.anr = :anr') - ->andWhere('v.code = :code') - ->setParameter('anr', $anr) - ->setParameter('code', $code) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult() !== null; - } - - /** - * @return Vulnerability[] - */ - public function findByAnr(Anr $anr): array - { - return $this->getRepository()->createQueryBuilder('v') - ->where('v.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - public function saveEntity(VulnerabilitySuperClass $vulnerability, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($vulnerability); - if ($flushAll) { - $em->flush(); - } - } -} diff --git a/src/Service/AmvService.php b/src/Service/AmvService.php deleted file mode 100644 index 8b7de18a..00000000 --- a/src/Service/AmvService.php +++ /dev/null @@ -1,11 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\AmvTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Amv', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'assetTable' => 'Monarc\FrontOffice\Model\Table\AssetTable', - 'instanceTable' => 'Monarc\Core\Model\Table\InstanceTable', - 'measureTable' => 'Monarc\FrontOffice\Model\Table\MeasureTable', - 'threatTable' => 'Monarc\FrontOffice\Model\Table\ThreatTable', - 'vulnerabilityTable' => 'Monarc\FrontOffice\Model\Table\VulnerabilityTable', - ]; -} diff --git a/src/Service/AnrAmvService.php b/src/Service/AnrAmvService.php index 6b844558..d6985b30 100755 --- a/src/Service/AnrAmvService.php +++ b/src/Service/AnrAmvService.php @@ -1,313 +1,432 @@ -get('entity')->getFiltersForService(); - - return $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $filtersCol), - $filterAnd, - $filterJoin, - $filterLeft - ); + $this->connectedUser = $connectedUserService->getConnectedUser(); } - /** - * @inheritdoc - */ - public function getFilteredCount($filter = null, $filterAnd = null) + public function getList(FormattedInputParams $params): array { - [$filterJoin, $filterLeft, $filtersCol] = $this->get('entity')->getFiltersForService(); - - return $this->get('table')->countFiltered( - $this->parseFrontendFilter($filter, $filtersCol), - $filterAnd, - $filterJoin, - $filterLeft - ); + $result = []; + /** @var Entity\Amv $amv */ + foreach ($this->amvTable->findByParams($params) as $amv) { + $result[] = $this->prepareAmvDataResult($amv); + } + + return $result; } - /** - * @inheritdoc - */ - public function update($id, $data) + public function getCount($params): int { - /** @var AmvTable $amvTable */ - $amvTable = $this->get('table'); - /** @var Amv $amv */ - $amv = $amvTable->findByUuidAndAnrId($id['uuid'], (int)$id['anr']); + return $this->amvTable->countByParams($params); + } + + public function getAmvData(Entity\Anr $anr, string $uuid): array + { + /** @var Entity\Amv $amv */ + $amv = $this->amvTable->findByUuidAndAnr($uuid, $anr); + + return $this->prepareAmvDataResult($amv, true); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\Amv + { + if ($this->amvTable + ->findByAmvItemsUuidsAndAnr($data['asset'], $data['threat'], $data['vulnerability'], $anr) !== null + ) { + throw new Exception('The informational risk already exists.', 412); + } + + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($data['asset'], $anr); + /** @var Entity\Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($data['threat'], $anr); + /** @var Entity\Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($data['vulnerability'], $anr); + + return $this->createAmvFromPreparedData($anr, $asset, $threat, $vulnerability, $data, $saveInDb); + } + + public function createAmvFromPreparedData( + Entity\Anr $anr, + Entity\Asset $asset, + Entity\Threat $threat, + Entity\Vulnerability $vulnerability, + array $data, + bool $saveInDb = true, + bool $createInstanceRisksForInstances = true + ): Entity\Amv { + $amv = (new Entity\Amv()) + ->setAnr($anr) + ->setAsset($asset) + ->setThreat($threat) + ->setVulnerability($vulnerability) + ->setCreator($this->connectedUser->getEmail()); + if (isset($data['uuid'])) { + $amv->setUuid($data['uuid']); + } + if (isset($data['status'])) { + $amv->setStatus($data['status']); + } + + foreach ($data['measures'] ?? [] as $measureUuid) { + /** @var Entity\Measure $measure */ + $measure = $this->measureTable->findByUuidAndAnr($measureUuid, $anr); + $amv->addMeasure($measure); + } + + $this->updatePositions($amv, $this->amvTable, $data); + + if ($createInstanceRisksForInstances) { + $this->createInstanceRiskForInstances($asset, $amv); + } + + $this->amvTable->save($amv, $saveInDb); + + return $amv; + } + + public function update(Entity\Anr $anr, string $uuid, array $data): Entity\Amv + { + /** @var Entity\Amv $amv */ + $amv = $this->amvTable->findByUuidAndAnr($uuid, $anr); - $linkedMeasuresUuids = array_column($data['measures'], 'uuid'); foreach ($amv->getMeasures() as $measure) { - $linkedMeasuresUuidKey = array_search($measure->getUuid(), $linkedMeasuresUuids, true); - if ($linkedMeasuresUuidKey === false) { + $linkedMeasuresUuidKey = array_search($measure->getUuid(), $data['measures'], true); + if ($linkedMeasuresUuidKey !== false) { + unset($data['measures'][$linkedMeasuresUuidKey]); + } else { $amv->removeMeasure($measure); - continue; } - - unset($data['measures'][$linkedMeasuresUuidKey]); } - /** @var MeasureTable $measureTable */ - $measureTable = $this->get('measureTable'); - foreach ($data['measures'] as $measure) { - $amv->addMeasure($measureTable->getEntity($measure)); + foreach ($data['measures'] as $measureUuid) { + /** @var Entity\Measure $measure */ + $measure = $this->measureTable->findByUuidAndAnr($measureUuid, $anr); + $amv->addMeasure($measure); } - $amv->setUpdater($this->getConnectedUser()->getFirstname() . ' ' . $this->getConnectedUser()->getLastname()); - - if ($this->isThreatChanged($data, $amv) || $this->isVulnerabilityChanged($data, $amv)) { - $newAmv = (new Amv()) - ->setUuid(Uuid::uuid4()) - ->setAnr($amv->getAnr()) - ->setAsset($amv->getAsset()) - ->setThreat($amv->getThreat()) - ->setVulnerability($amv->getVulnerability()) - ->setMeasures($amv->getMeasures()) - ->setPosition($amv->getPosition()) - ->setStatus($amv->getStatus()) - ->setCreator($amv->getUpdater()); - - if ($this->isThreatChanged($data, $amv)) { - /** @var ThreatTable $threatTable */ - $threatTable = $this->get('threatTable'); - $threat = $threatTable->findByAnrAndUuid($amv->getAnr(), $data['threat']); - $newAmv->setThreat($threat); - } - if ($this->isVulnerabilityChanged($data, $amv)) { - /** @var VulnerabilityTable $vulnerabilityTable */ - $vulnerabilityTable = $this->get('vulnerabilityTable'); - $vulnerability = $vulnerabilityTable->findByAnrAndUuid($amv->getAnr(), $data['vulnerability']); - $newAmv->setVulnerability($vulnerability); - } + $amv->setUpdater($this->connectedUser->getEmail()); + + $this->updatePositions($amv, $this->amvTable, $data); + + $isThreatChanged = $this->isThreatChanged($data, $amv); + if ($isThreatChanged) { + /** @var Entity\Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($data['threat'], $anr); + $amv->setThreat($threat); + } - /** @var InstanceRisk[] $instancesRisks */ - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('instanceRiskTable'); - $instancesRisks = $instanceRiskTable->findByAmv($amv); - foreach ($instancesRisks as $instanceRisk) { - $instanceRisk->setThreat($newAmv->getThreat()); - $instanceRisk->setVulnerability($newAmv->getVulnerability()); - $instanceRisk->setAmv($newAmv); + $isVulnerabilityChanged = $this->isVulnerabilityChanged($data, $amv); + if ($isVulnerabilityChanged) { + /** @var Entity\Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($data['vulnerability'], $anr); + $amv->setVulnerability($vulnerability); + } + if ($isThreatChanged || $isVulnerabilityChanged) { + foreach ($amv->getInstanceRisks() as $instanceRisk) { + $instanceRisk->setThreat($amv->getThreat()); + $instanceRisk->setVulnerability($amv->getVulnerability()); } + } + + $this->amvTable->save($amv); + + return $amv; + } - $amvTable->deleteEntity($amv, false); - $amv = $newAmv; + public function patch(Entity\Anr $anr, string $uuid, array $data): Entity\Amv + { + /** @var Entity\Amv $amv */ + $amv = $this->amvTable->findByUuidAndAnr($uuid, $anr); + if (isset($data['status'])) { + $amv->setStatus((int)$data['status'])->setUpdater($this->connectedUser->getEmail()); + $this->amvTable->save($amv); } - $amvTable->saveEntity($amv); + return $amv; } /** - * @inheritdoc + * Import of instance risks. + * + * @return string[] Created Amvs' uuids. */ - public function patch($id, $data) + public function createAmvItems(Entity\Anr $anr, array $data): array { - /** @var AmvTable $amvTable */ - $amvTable = $this->get('table'); - $amv = $amvTable->findByUuidAndAnrId($id['uuid'], (int)$data['anr']); + $createdAmvsUuids = []; + foreach ($data as $amvData) { + if (!isset($amvData['asset']['uuid'], $amvData['threat']['uuid'], $amvData['vulnerability']['uuid']) + || $this->amvTable->findByAmvItemsUuidsAndAnr( + $amvData['asset']['uuid'], + $amvData['threat']['uuid'], + $amvData['vulnerability']['uuid'], + $anr + ) !== null + ) { + continue; + } - if (isset($data['status'])) { - $amv->setStatus((int)$data['status']); + $asset = $this->getOrCreateAssetObject($anr, $amvData['asset']); + $threat = $this->getOrCreateThreatObject($anr, $amvData['threat']); + $vulnerability = $this->getOrCreateVulnerabilityObject($anr, $amvData['vulnerability']); + + $amv = (new Entity\Amv()) + ->setAnr($anr) + ->setAsset($asset) + ->setThreat($threat) + ->setVulnerability($vulnerability) + ->setCreator($this->connectedUser->getEmail()); + + $this->updatePositions($amv, $this->amvTable); + + $this->createInstanceRiskForInstances($asset, $amv); + + $this->amvTable->save($amv); + + $createdAmvsUuids[] = $amv->getUuid(); } - $amv->setUpdater($this->getConnectedUser()->getFirstname() . ' ' . $this->getConnectedUser()->getLastname()); - $amvTable->saveEntity($amv); + return $createdAmvsUuids; } /** - * @inheritdoc + * Links amv of destination to source depending on the measures_measures (map referential). */ - public function create($data, $last = true) - { - $class = $this->get('entity'); - /** @var Amv $amv */ - $amv = new $class(); - $amv->setLanguage($this->getLanguage()); - $amv->setDbAdapter($this->get('table')->getDb()); - - //manage the measures separately because it's the slave of the relation amv<-->measures - if (!empty($data['measures'])) { - foreach ($data['measures'] as $measure) { - $measureEntity = $this->get('measureTable')->getEntity($measure); - $measureEntity->addAmv($amv); + public function createLinkedAmvs( + Entity\Anr $anr, + string $sourceReferentialUuid, + string $destinationReferentialUuid + ): void { + /** @var Entity\Referential $referential */ + $referential = $this->referentialTable->findByUuidAndAnr($destinationReferentialUuid, $anr); + foreach ($referential->getMeasures() as $destinationMeasure) { + foreach ($destinationMeasure->getLinkedMeasures() as $measureLink) { + if ($measureLink->getReferential()->getUuid() === $sourceReferentialUuid) { + foreach ($measureLink->getAmvs() as $amv) { + $destinationMeasure->addAmv($amv); + } + $this->measureTable->save($destinationMeasure, false); + } } - unset($data['measures']); } - $amv->exchangeArray($data); - unset($data['measures']); - $dependencies = (property_exists($this, 'dependencies')) ? $this->dependencies : []; - $this->setDependencies($amv, $dependencies); - - $amv->setCreator( - $this->getConnectedUser()->getFirstname() . ' ' . $this->getConnectedUser()->getLastname() - ); - - /** @var AmvTable $table */ - $table = $this->get('table'); - $id = $table->save($amv, $last); - - // Create instances risks - /** @var MonarcObjectTable $MonarcObjectTable */ - $MonarcObjectTable = $this->get('MonarcObjectTable'); - $objects = $MonarcObjectTable->getEntityByFields([ - 'anr' => $data['anr'], - 'asset' => [ - 'uuid' => $amv->getAsset()->getUuid(), - 'anr' => $data['anr'] - ] - ]); - foreach ($objects as $object) { - /** @var InstanceTable $instanceTable */ - $instanceTable = $this->get('instanceTable'); - $instances = $instanceTable->getEntityByFields([ - 'anr' => $data['anr'], - 'object' => ['anr' => $data['anr'], 'uuid' => $object->getUuid()] - ]); - $i = 1; - $nbInstances = count($instances); - foreach ($instances as $instance) { - $instanceRisk = new InstanceRisk(); - - $instanceRisk->setLanguage($this->getLanguage()); - $instanceRisk->setDbAdapter($this->get('table')->getDb()); - $instanceRisk->setAnr($this->get('anrTable')->getEntity($data['anr'])); - $instanceRisk->setAmv($amv); - $instanceRisk->setAsset($amv->getAsset()); - $instanceRisk->setInstance($instance); - $instanceRisk->setThreat($amv->getThreat()); - $instanceRisk->setVulnerability($amv->getVulnerability()); + $this->measureTable->flush(); + } + + public function delete(Entity\Anr $anr, string $uuid): void + { + /** @var Entity\Amv $amv */ + $amv = $this->amvTable->findByUuidAndAnr($uuid, $anr); + $this->resetInstanceRisksRelation($amv); + $this->amvTable->remove($amv); + } - $this->get('instanceRiskTable')->save($instanceRisk, ($i == $nbInstances)); - $i++; + public function deleteList(Entity\Anr $anr, array $data): void + { + /** @var Entity\Amv $amv */ + foreach ($this->amvTable->findByUuidsAndAnr($data, $anr) as $amv) { + $this->resetInstanceRisksRelation($amv); + $this->amvTable->remove($amv); + } + } + + private function getOrCreateAssetObject(Entity\Anr $anr, array $assetData): Entity\Asset + { + if (!empty($assetData['uuid'])) { + try { + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($assetData['uuid'], $anr); + + return $asset; + } catch (EntityNotFoundException $e) { } } - return $id; + return $this->anrAssetService->create($anr, $assetData, false); } - /** - * @param array $id - * - * @throws EntityNotFoundException|ORMException - */ - public function delete($id) + private function getOrCreateThreatObject(Entity\Anr $anr, array $threatData): Entity\Threat { - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('instanceRiskTable'); - /** @var AmvTable $amvTable */ - $amvTable = $this->get('amvTable'); + if (!empty($threatData['uuid'])) { + try { + /** @var Entity\Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($threatData['uuid'], $anr); - $amv = $amvTable->findByUuidAndAnrId($id['uuid'], $id['anr']); - $this->resetInstanceRisksRelation($amv, $amvTable, $instanceRiskTable); + return $threat; + } catch (EntityNotFoundException $e) { + } + } + + if (isset($threatData['theme'])) { + $threatData['theme'] = $this->themeTable->findById((int)$threatData['theme']); + } - parent::delete($id); + return $this->anrThreatService->create($anr, $threatData, false); } - public function deleteListFromAnr($data, $anrId = null) + private function getOrCreateVulnerabilityObject(Entity\Anr $anr, array $vulnerabilityData): Entity\Vulnerability { - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - if ($anrId !== null) { - $anr = $anrTable->findById($anrId); + if (!empty($vulnerabilityData['uuid'])) { + try { + /** @var Entity\Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($vulnerabilityData['uuid'], $anr); - $this->validateAnrPermissions($anr, $data); + return $vulnerability; + } catch (EntityNotFoundException $e) { + } } - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('instanceRiskTable'); - /** @var AmvTable $amvTable */ - $amvTable = $this->get('amvTable'); + return $this->anrVulnerabilityService->create($anr, $vulnerabilityData); + } - foreach ($data as $amvId) { - $amv = $amvTable->findByUuidAndAnrId($amvId['uuid'], $amvId['anr']); - $this->resetInstanceRisksRelation($amv, $amvTable, $instanceRiskTable); + /** + * Created instance risks based on the newly created AMV for the instances based on the linked asset. + */ + private function createInstanceRiskForInstances(Entity\Asset $asset, Entity\Amv $amv): void + { + foreach ($asset->getInstances() as $instance) { + $this->anrInstanceRiskService->createInstanceRisk($instance, $amv); } - - return $this->get('table')->deleteList($data); } - protected function isThreatChanged(array $data, AmvSuperClass $amv): bool + private function isThreatChanged(array $data, AmvSuperClass $amv): bool { return $amv->getThreat()->getUuid() !== $data['threat']; } - protected function isVulnerabilityChanged(array $data, AmvSuperClass $amv): bool + private function isVulnerabilityChanged(array $data, AmvSuperClass $amv): bool { return $amv->getVulnerability()->getUuid() !== $data['vulnerability']; } - /** - * @throws ORMException - */ - private function resetInstanceRisksRelation( - Amv $amv, - AmvTable $amvTable, - InstanceRiskTable $instanceRiskTable - ): void { + private function resetInstanceRisksRelation(Entity\Amv $amv): void + { foreach ($amv->getInstanceRisks() as $instanceRisk) { $instanceRisk->setAmv(null) ->setSpecific(InstanceRiskSuperClass::TYPE_SPECIFIC) - ->setUpdater($amvTable->getConnectedUser()->getEmail()); + ->setUpdater($this->connectedUser->getEmail()); - $instanceRiskTable->saveEntity($instanceRisk); + $this->instanceRiskTable->save($instanceRisk); // TODO: remove it when double fields relation is removed. - $instanceRiskTable->getDb()->getEntityManager()->refresh($instanceRisk); - $instanceRiskTable->saveEntity($instanceRisk->setAnr($amv->getAnr())); + $this->instanceRiskTable->refresh($instanceRisk); + $this->instanceRiskTable->save($instanceRisk->setAnr($amv->getAnr())); } } + + private function prepareAmvDataResult(Entity\Amv $amv, bool $includePositionFields = false): array + { + $measures = []; + foreach ($amv->getMeasures() as $measure) { + $referential = $measure->getReferential(); + $measures[] = [ + 'uuid' => $measure->getUuid(), + 'code' => $measure->getCode(), + 'label1' => $measure->getLabel(1), + 'label2' => $measure->getLabel(2), + 'label3' => $measure->getLabel(3), + 'label4' => $measure->getLabel(4), + 'referential' => [ + 'uuid' => $referential->getUuid(), + 'label1' => $referential->getLabel(1), + 'label2' => $referential->getLabel(2), + 'label3' => $referential->getLabel(3), + 'label4' => $referential->getLabel(4), + ] + ]; + } + + $result = array_merge([ + 'uuid' => $amv->getUuid(), + 'measures' => $measures, + 'status' => $amv->getStatus(), + 'position' => $amv->getPosition(), + ], $this->getAmvRelationsData($amv)); + + if ($includePositionFields) { + $result['implicitPosition'] = 1; + if ($amv->getPosition() > 1) { + $maxPositionByAsset = $this->amvTable->findMaxPosition($amv->getImplicitPositionRelationsValues()); + if ($maxPositionByAsset === $amv->getPosition()) { + $result['implicitPosition'] = 2; + } else { + /** @var Entity\Asset $asset */ + $asset = $amv->getAsset(); + $previousAmv = $this->amvTable->findByAssetAndPosition($asset, $amv->getPosition() - 1); + if ($previousAmv !== null) { + $result['implicitPosition'] = 3; + $result['previous'] = array_merge([ + 'uuid' => $previousAmv->getUuid(), + 'position' => $previousAmv->getPosition(), + ], $this->getAmvRelationsData($previousAmv)); + } + } + } + } + + return $result; + } + + private function getAmvRelationsData(Entity\Amv $amv): array + { + $asset = $amv->getAsset(); + $threat = $amv->getThreat(); + $themeData = $threat->getTheme() !== null + ? array_merge(['id' => $threat->getTheme()->getId()], $threat->getTheme()->getLabels()) + : null; + $vulnerability = $amv->getVulnerability(); + + return [ + 'asset' => array_merge([ + 'uuid' => $asset->getUuid(), + 'code' => $asset->getCode(), + ], $asset->getLabels()), + 'threat' => array_merge([ + 'uuid' => $threat->getUuid(), + 'code' => $threat->getCode(), + 'theme' => $themeData, + ], $threat->getLabels()), + 'vulnerability' => array_merge([ + 'uuid' => $vulnerability->getUuid(), + 'code' => $vulnerability->getCode(), + ], $vulnerability->getLabels()), + ]; + } } diff --git a/src/Service/AnrAmvServiceFactory.php b/src/Service/AnrAmvServiceFactory.php deleted file mode 100755 index 6d68aee6..00000000 --- a/src/Service/AnrAmvServiceFactory.php +++ /dev/null @@ -1,40 +0,0 @@ - Amv::class, - 'table' => Table\AmvTable::class, - 'anrTable' => Table\AnrTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'assetTable' => Table\AssetTable::class, - 'threatTable' => Table\ThreatTable::class, - 'vulnerabilityTable' => Table\VulnerabilityTable::class, - 'measureTable' => Table\MeasureTable::class, - 'referentialTable' => Table\ReferentialTable::class, - 'amvTable' => Table\AmvTable::class, - 'instanceTable' => Table\InstanceTable::class, - 'instanceRiskTable' => Table\InstanceRiskTable::class, - 'MonarcObjectTable' => Table\MonarcObjectTable::class, - 'assetService' => Service\AnrAssetService::class, - 'threatService' => Service\AnrThreatService::class, - 'vulnerabilityService' => Service\AnrVulnerabilityService::class, - 'themeTable' => Table\ThemeTable::class, - ]; -} diff --git a/src/Service/AnrAssetCommonService.php b/src/Service/AnrAssetCommonService.php deleted file mode 100755 index b52db90f..00000000 --- a/src/Service/AnrAssetCommonService.php +++ /dev/null @@ -1,194 +0,0 @@ -get('anrTable')->getEntity($anrId); - if ($anr) { - $model = $this->get('coreServiceAsset')->get('modelTable')->getEntity($anr->get('model')); - - $assets = $this->get('table')->getRepository()->createQueryBuilder('a'); - $fctWhere = 'where'; - if ($model->get('isGeneric') || !$model->get('isRegulator')) { - $assets = $assets->where('a.mode = :mode') - ->setParameter(':mode', 0); // generic - $fctWhere = 'andWhere'; - } - if (!$model->get('isGeneric')) { - $assets = $assets->innerJoin('a.models', 'm') - ->$fctWhere('m.id = :mid') - ->setParameter(':mid', $anr->get('model')); - } - - $assets = $assets->orderBy('a.code', 'ASC') - ->getQuery()->getResult(); - $return = []; - $aObj = [ - 'id', - 'label' . $anr->get('language'), - 'description' . $anr->get('language'), - 'status', - 'mode', - 'type', - 'code', - ]; - foreach ($assets as $a) { - $return[] = $a->getJsonArray($aObj); - } - return $return; - } else { - throw new \Monarc\Core\Exception\Exception('Anr does not exist', 412); - } - } - - /** - * Returns a specific asset data as an array - * @param int $anrId The ANR ID - * @param int $assetId The asset ID - * @return array The asset fields - * @throws \Monarc\Core\Exception\Exception If the ANR mismatches or the entity does not exist - */ - public function getAsset($anrId, $assetId) - { - $anr = $this->get('anrTable')->getEntity($anrId); - if ($anr) { - $model = $this->get('coreServiceAsset')->get('modelTable')->getEntity($anr->get('model')); - - $asset = $this->get('table')->getRepository()->createQueryBuilder('a'); - $asset = $asset->where('a.id = :assetId')->setParameter(':assetId', $assetId); - $fctWhere = 'andWhere'; - if ($model->get('isGeneric') || !$model->get('isRegulator')) { - $asset = $asset->andWhere('a.mode = :mode') - ->setParameter(':mode', 0); // generic - $fctWhere = 'andWhere'; - } - if (!$model->get('isGeneric')) { - $asset = $asset->innerJoin('a.models', 'm') - ->$fctWhere('m.id = :mid') - ->setParameter(':mid', $anr->get('model')); - } - $asset = $asset->setFirstResult(0)->setMaxResults(1) - ->getQuery()->getSingleResult(); - if ($asset) { - $return = $asset->getJsonArray([ - 'id', - 'label' . $anr->get('language'), - 'description' . $anr->get('language'), - 'status', - 'mode', - 'type', - 'code', - ]); - $return['amvs'] = []; - $amvs = $this->get('amvTable')->getRepository()->createQueryBuilder('t') - ->where('t.asset = :aid') - ->setParameter(':aid', $return['id'])// add orders - ->getQuery()->getResult(); - foreach ($amvs as $amv) { - $amvArray = [ - 'threat' => [ - 'code' => $amv->get('threat')->get('code'), - 'label' . $anr->get('language') => $amv->get('threat')->get('label' . $anr->get('language')), - ], - 'vulnerability' => [ - 'code' => $amv->get('vulnerability')->get('code'), - 'label' . $anr->get('language') => $amv->get('vulnerability')->get('label' . $anr->get('language')), - ], - ]; - for ($i = 1; $i <= 3; $i++) { - $amvArray['measure' . $i] = [ - 'code' => null, - 'description' . $anr->get('language') => null, - ]; - if ($amv->get('measure' . $i)) { - $amvArray['measure' . $i] = [ - 'code' => $amv->get('measure' . $i)->get('code'), - 'description' . $anr->get('language') => $amv->get('measure' . $i)->get('description' . $anr->get('language')), - ]; - } - } - $return['amvs'][] = $amvArray; - } - return $return; - } else { - throw new \Monarc\Core\Exception\Exception('Asset does not exist', 412); - } - } else { - throw new \Monarc\Core\Exception\Exception('Anr does not exist', 412); - } - } - - /** - * Imports an asset from the common knowledge base (common database) into the provided client (local) ANR - * @param int $anrId The target ANR ID - * @param int $assetId The common asset ID to import - * @return int The generated asset ID - * @throws \Monarc\Core\Exception\Exception If the asset or ANR does not exist - */ - public function importAsset($anrId, $assetId) - { - $anr = $this->get('anrTable')->getEntity($anrId); - - if ($anr) { - // Lookup the asset inside the common database - $model = $this->get('coreServiceAsset')->get('modelTable')->getEntity($anr->get('model')); - - $asset = $this->get('table')->getRepository()->createQueryBuilder('a'); - $asset->where('a.id = :assetId')->setParameter(':assetId', $assetId); - - $fctWhere = 'andWhere'; - if ($model->get('isGeneric') || !$model->get('isRegulator')) { - $asset = $asset->andWhere('a.mode = :mode') - ->setParameter(':mode', 0); // generic - $fctWhere = 'andWhere'; - } - if (!$model->get('isGeneric')) { - $asset = $asset->innerJoin('a.models', 'm') - ->$fctWhere('m.id = :mid') - ->setParameter(':mid', $anr->get('model')); - } - $asset = $asset->setFirstResult(0)->setMaxResults(1) - ->getQuery()->getSingleResult(); // même si on fait une autre requête dans AssetService::generateExportArray(), cela permet d'avoir un contrôle sur asset_id & model_id - - if ($asset) { - /* - - faire un export de cet asset - - utiliser l'import déjà en place - */ - $f = null; - $data = $this->get('coreServiceAsset')->get('assetExportService')->generateExportArray($asset->get('id'), $f); - return $this->get('cliServiceAsset')->importFromArray($data, $anr); - } else { - throw new \Monarc\Core\Exception\Exception('Asset does not exist', 412); - } - } else { - throw new \Monarc\Core\Exception\Exception('Anr does not exist', 412); - } - } -} diff --git a/src/Service/AnrAssetCommonServiceFactory.php b/src/Service/AnrAssetCommonServiceFactory.php deleted file mode 100755 index 8d4a31cd..00000000 --- a/src/Service/AnrAssetCommonServiceFactory.php +++ /dev/null @@ -1,28 +0,0 @@ - 'Monarc\Core\Model\Entity\Asset', - 'table' => 'Monarc\Core\Model\Table\AssetTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'amvTable' => 'Monarc\Core\Model\Table\AmvTable', - 'clientity' => 'Monarc\FrontOffice\Model\Entity\Asset', - 'clitable' => 'Monarc\FrontOffice\Model\Table\AssetTable', - 'coreServiceAsset' => 'Monarc\Core\Service\AssetService', - 'cliServiceAsset' => 'Monarc\FrontOffice\Service\AnrAssetService', - ]; -} diff --git a/src/Service/AnrAssetService.php b/src/Service/AnrAssetService.php index 3b81ad06..ed950ef9 100755 --- a/src/Service/AnrAssetService.php +++ b/src/Service/AnrAssetService.php @@ -1,33 +1,144 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $params): array + { + $result = []; + /** @var Entity\Asset $asset */ + foreach ($this->assetTable->findByParams($params) as $asset) { + $result[] = $this->prepareAssetDataResult($asset); + } + + return $result; + } + + public function getCount(FormattedInputParams $params): int + { + return $this->assetTable->countByParams($params); + } + + public function getAssetData(Entity\Anr $anr, string $uuid): array + { + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($uuid, $anr); + + return $this->prepareAssetDataResult($asset); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\Asset + { + /** @var Entity\Asset $asset */ + $asset = (new Entity\Asset()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setType($data['type']) + ->setCreator($this->connectedUser->getEmail()); + if (isset($data['uuid'])) { + $asset->setUuid($data['uuid']); + } + if (isset($data['status'])) { + $asset->setStatus($data['status']); + } + + $this->assetTable->save($asset, $saveInDb); + + return $asset; + } + + public function createList(Entity\Anr $anr, array $data): array + { + $createdUuids = []; + foreach ($data as $row) { + $createdUuids[] = $this->create($anr, $row, false)->getUuid(); + } + $this->assetTable->flush(); + + return $createdUuids; + } + + public function update(Entity\Anr $anr, string $uuid, array $data): Entity\Asset + { + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($uuid, $anr); + + $asset->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setType((int)$data['type']) + ->setStatus($data['status'] ?? CoreEntity\AssetSuperClass::STATUS_ACTIVE) + ->setUpdater($this->connectedUser->getEmail()); + + $this->assetTable->save($asset); + + return $asset; + } + + public function patch(Entity\Anr $anr, string $uuid, array $data): Entity\Asset + { + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($uuid, $anr); + + if (isset($data['status'])) { + $asset->setStatus((int)$data['status']) + ->setUpdater($this->connectedUser->getEmail()); + + $this->assetTable->save($asset); + } + + return $asset; + } + + public function delete(Entity\Anr $anr, string $uuid): void + { + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($uuid, $anr); + + $this->assetTable->remove($asset); + } + + public function deleteList(Entity\Anr $anr, array $data): void + { + $assets = $this->assetTable->findByUuidsAndAnr($data, $anr); + + $this->assetTable->removeList($assets); + } + + public function prepareAssetDataResult(Entity\Asset $asset): array + { + return array_merge($asset->getLabels(), $asset->getDescriptions(), [ + 'uuid' => $asset->getUuid(), + 'anr' => [ + 'id' => $asset->getAnr()->getId(), + ], + 'code' => $asset->getCode(), + 'type' => $asset->getType(), + 'status' => $asset->getStatus(), + 'mode' => $asset->getMode(), + ]); + } } diff --git a/src/Service/AnrAssetServiceFactory.php b/src/Service/AnrAssetServiceFactory.php deleted file mode 100755 index ea11cb09..00000000 --- a/src/Service/AnrAssetServiceFactory.php +++ /dev/null @@ -1,23 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Asset', - 'table' => 'Monarc\FrontOffice\Model\Table\AssetTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - ]; -} diff --git a/src/Service/AnrCartoRiskService.php b/src/Service/AnrCartoRiskService.php index 45805d7a..8cf27aae 100755 --- a/src/Service/AnrCartoRiskService.php +++ b/src/Service/AnrCartoRiskService.php @@ -1,140 +1,123 @@ -buildListScalesAndHeaders($anrId); - $this->buildListScalesOpRisk($anrId); + $this->buildListScalesAndHeaders($anr); + $this->buildListScalesOpRisk($anr); - list($counters, $distrib, $riskMaxSum, $byTreatment) = $this->getCountersRisks('raw'); - list($countersRiskOP, $distribRiskOp, $riskOpMaxSum, $byTreatmentRiskOp) = $this->getCountersOpRisks('raw'); + [$counters, $distrib, $riskMaxSum, $byTreatment] = $this->getCountersRisks($anr); + [$countersRiskOP, $distribRiskOp, $riskOpMaxSum, $byTreatmentRiskOp] = $this->getCountersOpRisks($anr); return [ - 'Impact' => $this->listScales[Scale::TYPE_IMPACT], - 'Probability' => $this->listScales[Scale::TYPE_THREAT], - 'OpRiskImpact' => $this->listOpRiskScales[OperationalRiskScale::TYPE_IMPACT], - 'Likelihood' => $this->listOpRiskScales[OperationalRiskScale::TYPE_LIKELIHOOD], + 'Impact' => $this->listScales[CoreEntity\ScaleSuperClass::TYPE_IMPACT], + 'Probability' => $this->listScales[CoreEntity\ScaleSuperClass::TYPE_THREAT], + 'OpRiskImpact' => $this->listOpRiskScales[CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT], + 'Likelihood' => $this->listOpRiskScales[CoreEntity\OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD], 'MxV' => $this->headers, 'riskInfo' => [ - 'counters' => $counters, - 'distrib' => $distrib, - 'riskMaxSum' => $riskMaxSum, - 'byTreatment' => $byTreatment, + 'counters' => $counters, + 'distrib' => $distrib, + 'riskMaxSum' => $riskMaxSum, + 'byTreatment' => $byTreatment, ], 'riskOp' => [ - 'counters' => $countersRiskOP, - 'distrib' => $distribRiskOp, - 'riskOpMaxSum' => $riskOpMaxSum, - 'byTreatment' => $byTreatmentRiskOp, + 'counters' => $countersRiskOP, + 'distrib' => $distribRiskOp, + 'riskOpMaxSum' => $riskOpMaxSum, + 'byTreatment' => $byTreatmentRiskOp, ], ]; } /** - * Computes and returns the cartography of targeted risks - * @param int $anrId The ANR ID - * @return array An associative array of Impact (rows), MxV (columns), counters and distrib to display as a table + * Computes and returns the cartography of targeted risks. + * + * @return array An associative array of Impact (rows), MxV (columns), counters and distrib to display as a table. */ - public function getCartoTargeted($anrId) + public function getCartoTargeted(Entity\Anr $anr): array { - $this->buildListScalesAndHeaders($anrId); - $this->buildListScalesOpRisk($anrId); + $this->buildListScalesAndHeaders($anr); + $this->buildListScalesOpRisk($anr); - list($counters, $distrib, $riskMaxSum, $byTreatment) = $this->getCountersRisks('target'); - list($countersRiskOP, $distribRiskOp, $riskOpMaxSum, $byTreatmentRiskOp) = $this->getCountersOpRisks('target'); + [$counters, $distrib, $riskMaxSum, $byTreatment] = $this->getCountersRisks($anr, 'target'); + [$countersRiskOP, $distribRiskOp, $riskOpMaxSum, $byTreatmentRiskOp] = $this->getCountersOpRisks( + $anr, + 'target' + ); return [ - 'Impact' => $this->listScales[Scale::TYPE_IMPACT], - 'Probability' => $this->listScales[Scale::TYPE_THREAT], - 'OpRiskImpact' => $this->listOpRiskScales[OperationalRiskScale::TYPE_IMPACT], - 'Likelihood' => $this->listOpRiskScales[OperationalRiskScale::TYPE_LIKELIHOOD], + 'Impact' => $this->listScales[CoreEntity\ScaleSuperClass::TYPE_IMPACT], + 'Probability' => $this->listScales[CoreEntity\ScaleSuperClass::TYPE_THREAT], + 'OpRiskImpact' => $this->listOpRiskScales[CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT], + 'Likelihood' => $this->listOpRiskScales[CoreEntity\OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD], 'MxV' => $this->headers, 'riskInfo' => [ - 'counters' => $counters, - 'distrib' => $distrib, - 'riskMaxSum' => $riskMaxSum, - 'byTreatment' => $byTreatment, + 'counters' => $counters, + 'distrib' => $distrib, + 'riskMaxSum' => $riskMaxSum, + 'byTreatment' => $byTreatment, ], 'riskOp' => [ - 'counters' => $countersRiskOP, - 'distrib' => $distribRiskOp, - 'riskOpMaxSum' => $riskOpMaxSum, - 'byTreatment' => $byTreatmentRiskOp, + 'counters' => $countersRiskOP, + 'distrib' => $distribRiskOp, + 'riskOpMaxSum' => $riskOpMaxSum, + 'byTreatment' => $byTreatmentRiskOp, ], ]; - } + } /** - * Computes and builds the List Scales and headers for the table (Impact and MxV fields) - * @param int $anrId The ANR ID + * Computes and builds the List Scales and headers for the table (Impact and MxV fields). */ - public function buildListScalesAndHeaders($anrId) + public function buildListScalesAndHeaders(Entity\Anr $anr) { - // Only load the ANR if we don't have the ANR already loaded, or a different one. - if (!$this->anr || $this->anr->get('id') != $anrId) { - $this->anr = $this->get('anrTable')->getEntity($anrId); - } - // Only compute the listScales and headers fields if we didn't already - // TODO: If we reuse the service to build the carto for 2 different ANRs in the same run, this will cause issues! - if ($this->listScales === null) { - /** @var ScaleTable $scaleTable */ - $scaleTable = $this->get('table'); - $scales = $scaleTable->findByAnr($this->anr); - - $this->listScales = [ - Scale::TYPE_IMPACT => [], - Scale::TYPE_THREAT => [], - Scale::TYPE_VULNERABILITY => [], - ]; - foreach ($scales as $scale) { + // TODO: If we reuse the service to build the carto for 2 different ANRs in the same run, + // this will cause issues! + if ($this->listScales === []) { + foreach ($this->scalesCacheHelper->getCachedScales($anr) as $scale) { $this->listScales[$scale->getType()] = range($scale->getMin(), $scale->getMax()); } } - if ($this->headers === null) { - $this->headers = []; - foreach ($this->listScales[Scale::TYPE_IMPACT] as $i) { - foreach ($this->listScales[Scale::TYPE_THREAT] as $m) { - foreach ($this->listScales[Scale::TYPE_VULNERABILITY] as $v) { + if ($this->headers === []) { + foreach ($this->listScales[CoreEntity\ScaleSuperClass::TYPE_IMPACT] as $i) { + foreach ($this->listScales[CoreEntity\ScaleSuperClass::TYPE_THREAT] as $m) { + foreach ($this->listScales[CoreEntity\ScaleSuperClass::TYPE_VULNERABILITY] as $v) { $val = -1; if ($i !== -1 && $m !== -1 && $v !== -1) { $val = $m * $v; @@ -150,22 +133,20 @@ public function buildListScalesAndHeaders($anrId) } /** - * Computes and builds the List Scales for the operational risk table (Impact and likelihood fields) - * @param int $anrId The ANR ID + * Computes and builds the List Scales for the operational risk table (Impact and likelihood fields). */ - public function buildListScalesOpRisk($anrId) + public function buildListScalesOpRisk(Entity\Anr $anr) { - // Only load the ANR if we don't have the ANR already loaded, or a different one. - if (!$this->anr || $this->anr->get('id') != $anrId) { - $this->anr = $this->get('anrTable')->getEntity($anrId); - } - // Only compute the listScales and headers fields if we didn't already - if ($this->listOpRiskScales === null) { - /** @var OperationalRiskScaleTable $operationalRiskScaleTable */ - $operationalRiskScaleTable = $this->get('operationalRiskScaleTable'); - $likelihoodScale = current($operationalRiskScaleTable->findWithCommentsByAnrAndType($this->anr, OperationalRiskScale::TYPE_LIKELIHOOD)); - $impactsScale = current($operationalRiskScaleTable->findWithCommentsByAnrAndType($this->anr, OperationalRiskScale::TYPE_IMPACT)); + if ($this->listOpRiskScales === []) { + $likelihoodScale = current($this->operationalRiskScaleTable->findWithCommentsByAnrAndType( + $anr, + CoreEntity\OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD + )); + $impactsScale = current($this->operationalRiskScaleTable->findWithCommentsByAnrAndType( + $anr, + CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT + )); $impactScaleTypes = $impactsScale->getOperationalRiskScaleTypes(); $impactScaleComments = $impactScaleTypes[0]->getOperationalRiskScaleComments(); @@ -179,37 +160,27 @@ public function buildListScalesOpRisk($anrId) return $a <=> $b; }); - $this->listOpRiskScales[OperationalRiskScale::TYPE_IMPACT] = $impactScaleValues; - $this->listOpRiskScales[OperationalRiskScale::TYPE_LIKELIHOOD] = range($likelihoodScale->getMin(),$likelihoodScale->getMax()); + $this->listOpRiskScales[CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT] = $impactScaleValues; + $this->listOpRiskScales[CoreEntity\OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD] = range( + $likelihoodScale->getMin(), + $likelihoodScale->getMax() + ); } } /** - * Calculates the number of risks for each impact/MxV combo + * Calculates the number of risks for each impact/MxV combo. + * * @param string $mode The mode to use, either 'raw' or 'target' + * * @return array Associative array of values to show in the table */ - public function getCountersRisks($mode = 'raw') + public function getCountersRisks(Entity\Anr $anr, string $mode = 'raw') { - // On croise avec les données des risques - $changeField = $mode == 'raw' ? 'ir.cacheMaxRisk' : 'ir.cacheTargetedRisk'; - $query = $this->get('instanceRiskTable')->getRepository()->createQueryBuilder('ir'); - $result = $query->select([ - 'ir.id as myid', - 'ir.kindOfMeasure as treatment', - 'IDENTITY(ir.amv) as amv', 'IDENTITY(ir.asset) as asset', 'IDENTITY(ir.threat) as threat', 'IDENTITY(ir.vulnerability) as vulnerability', - $changeField . ' as maximus', - 'i.c as ic', 'i.i as ii', 'i.d as id', 'IDENTITY(i.object) as object', - 'm.c as mc', 'm.i as mi', 'm.a as ma', - 'o.scope', - ])->where('ir.anr = :anrid') - ->setParameter(':anrid', $this->anr->get('id')) - ->andWhere($changeField . " != -1") - ->innerJoin('ir.instance', 'i') - ->innerJoin('ir.threat', 'm') - ->innerJoin('i.object', 'o')->getQuery()->getResult(); - - $counters = $distrib = $riskMaxSum = $temp = []; + $temp = []; + $riskMaxSum = $temp; + $distrib = $temp; + $counters = $temp; $byTreatment = [ 'treated' => [], 'not_treated' => [], @@ -223,10 +194,13 @@ public function getCountersRisks($mode = 'raw') 'accepted' => [], 'shared' => [], 'not_treated' => [], - ] + ], ]; - foreach ($result as $r) { + $riskValueField = $mode === 'raw' ? 'ir.cacheMaxRisk' : 'ir.cacheTargetedRisk'; + foreach ($this->instanceRiskTable->findRisksValuesForCartoStatsByAnr($anr, $riskValueField) as $r) { + /** @var Entity\InstanceRisk $instanceRisk */ + $instanceRisk = $r['instanceRisk']; if (!isset($r['threat']) || !isset($r['vulnerability'])) { continue; } @@ -253,17 +227,19 @@ public function getCountersRisks($mode = 'raw') 'right' => $right, 'amv' => $r['asset'] . ';' . $r['threat'] . ';' . $r['vulnerability'], 'max' => $max, - 'color' => $this->getColor($max,'riskInfo'), - 'treatment' => $r['treatment'] + 'color' => $this->getColor($anr, $max), + 'treatment' => $instanceRisk->getTreatmentServiceName(), + 'isTreated' => $instanceRisk->isTreated(), ]; // on est obligé de faire l'algo en deux passes pour pouvoir compter les objets globaux qu'une seule fois - if ($r['scope'] == MonarcObject::SCOPE_GLOBAL) { + if ($r['scope'] === CoreEntity\ObjectSuperClass::SCOPE_GLOBAL) { if (!isset($temp[$r['object']][$context['amv']][0])) { // dans ce cas pas grand chose à faire on doit stocker le context local $temp[$r['object']][$context['amv']][0] = $context; } else { - // dans ce cas on doit comparer la valeur max qu'on a. Si c'est plus haut alors on remplace par le contexte courant + // dans ce cas on doit comparer la valeur max qu'on a. Si c'est plus haut alors on remplace par le + // contexte courant $cur = $temp[$r['object']][$context['amv']][0]; // Si on a un max plus grand, on le remplace, sinon on ne fait rien @@ -273,8 +249,9 @@ public function getCountersRisks($mode = 'raw') } } } else { - // pour les locaux, l'amv peut exister plusieurs fois sur le même biblio, du coup pour bien les compter plusieurs fois on rajoute - $temp[$r['object']][$context['amv']][$r['myid']] = $context; + // pour les locaux, l'amv peut exister plusieurs fois sur le même biblio, du coup pour bien les + // compter plusieurs fois on rajoute + $temp[$r['object']][$context['amv']][$instanceRisk->getId()] = $context; } } @@ -300,10 +277,10 @@ public function getCountersRisks($mode = 'raw') } $counters[$context['impact']][$context['right']] += 1; - $distrib[$context['color']] += 1; + ++$distrib[$context['color']]; $riskMaxSum[$context['color']] += $context['max']; - if ($context['treatment'] !== 5) { + if ($context['isTreated'] !== 5) { if (!isset($byTreatment['treated'][$context['color']]['count'])) { $byTreatment['treated'][$context['color']]['count'] = 0; } @@ -316,46 +293,28 @@ public function getCountersRisks($mode = 'raw') $byTreatment['treated'][$context['color']]['sum'] += $context['max']; } - switch($context['treatment']) { - case 1: - $kindOfTreatment = 'reduction'; - break; - case 2: - $kindOfTreatment = 'denied'; - break; - case 3: - $kindOfTreatment = 'accepted'; - break; - case 4: - $kindOfTreatment = 'shared'; - break; - case 5: - $kindOfTreatment = 'not_treated'; - break; - } - - - if (!isset($byTreatment['all'][$kindOfTreatment]['count'])) { - $byTreatment['all'][$kindOfTreatment]['count'] = 0; + $kindOfMeasure = $context['treatment']; + if (!isset($byTreatment['all'][$kindOfMeasure]['count'])) { + $byTreatment['all'][$kindOfMeasure]['count'] = 0; } - if (!isset($byTreatment['all'][$kindOfTreatment]['sum'])) { - $byTreatment['all'][$kindOfTreatment]['sum'] = 0; + if (!isset($byTreatment['all'][$kindOfMeasure]['sum'])) { + $byTreatment['all'][$kindOfMeasure]['sum'] = 0; } - if (!isset($byTreatment[$kindOfTreatment][$context['color']]['count'])) { - $byTreatment[$kindOfTreatment][$context['color']]['count'] = 0; + if (!isset($byTreatment[$kindOfMeasure][$context['color']]['count'])) { + $byTreatment[$kindOfMeasure][$context['color']]['count'] = 0; } - if (!isset($byTreatment[$kindOfTreatment][$context['color']]['sum'])) { - $byTreatment[$kindOfTreatment][$context['color']]['sum'] = 0; + if (!isset($byTreatment[$kindOfMeasure][$context['color']]['sum'])) { + $byTreatment[$kindOfMeasure][$context['color']]['sum'] = 0; } - $byTreatment[$kindOfTreatment][$context['color']]['count'] += 1; - $byTreatment[$kindOfTreatment][$context['color']]['sum'] += $context['max']; + $byTreatment[$kindOfMeasure][$context['color']]['count'] += 1; + $byTreatment[$kindOfMeasure][$context['color']]['sum'] += $context['max']; - $byTreatment['all'][$kindOfTreatment]['count'] += 1; - $byTreatment['all'][$kindOfTreatment]['sum'] += $context['max']; + $byTreatment['all'][$kindOfMeasure]['count'] += 1; + $byTreatment['all'][$kindOfMeasure]['sum'] += $context['max']; } } } @@ -364,25 +323,17 @@ public function getCountersRisks($mode = 'raw') } /** - * Calculates the number of operational risks for each impact/probabiliy combo + * Calculates the number of operational risks for each impact/probability combo. + * * @param string $mode The mode to use, either 'raw' or 'target' + * * @return array Associative array of values to show in the table */ - public function getCountersOpRisks($mode = 'raw') + public function getCountersOpRisks(Entity\Anr $anr, string $mode = 'raw') { - $valuesField = ['IDENTITY(iro.rolfRisk) as id', 'iro.netProb as netProb','iro.targetedProb as targetedProb']; - $query = $this->get('instanceRiskOpTable')->getRepository()->createQueryBuilder('iro'); - $result = $query->select([ - 'iro as instanceRiskOp', 'iro.cacheNetRisk as netRisk', 'iro.cacheTargetedRisk as targetedRisk', - 'iro.kindOfMeasure as treatment', - implode(',', $valuesField) - ])->where('iro.anr = :anrid') - ->setParameter(':anrid', $this->anr->get('id')) - ->andWhere("iro.cacheNetRisk != -1") - ->getQuery()->getResult(); - - - $countersRiskOP = $distribRiskOp = $riskOpMaxSum = $temp = []; + $riskOpMaxSum = []; + $distribRiskOp = $riskOpMaxSum; + $countersRiskOP = $riskOpMaxSum; $byTreatment = [ 'treated' => [], 'not_treated' => [], @@ -396,18 +347,20 @@ public function getCountersOpRisks($mode = 'raw') 'accepted' => [], 'shared' => [], 'not_treated' => [], - ] + ], ]; - foreach ($result as $r) { - foreach ($r['instanceRiskOp']->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { + foreach ($this->instanceRiskOpTable->findRisksValuesForCartoStatsByAnr($anr) as $r) { + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + $operationalInstanceRisk = $r['instanceRiskOp']; + foreach ($operationalInstanceRisk->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { $operationalRiskScaleType = $operationalInstanceRiskScale->getOperationalRiskScaleType(); $scalesData[$operationalRiskScaleType->getId()] = [ 'netValue' => $operationalInstanceRiskScale->getNetValue(), 'targetedValue' => $operationalInstanceRiskScale->getTargetedValue(), ]; } - if ($mode == 'raw' || $r['targetedRisk'] == -1) { + if ($mode === 'raw' || $r['targetedRisk'] === -1) { $imax = array_reduce($scalesData, function ($a, $b) { return $a ? ($a['netValue'] > $b['netValue'] ? $a : $b) : $b; }); @@ -422,8 +375,7 @@ public function getCountersOpRisks($mode = 'raw') $max = $r['targetedRisk']; $prob = $r['targetedProb']; } - $treatment = $r['treatment']; - $color = $this->getColor($max, 'riskOp'); + $color = $this->getColor($anr, $max, 'riskOp'); if (!isset($countersRiskOP[$imax][$prob])) { $countersRiskOP[$imax][$prob] = 0; @@ -438,10 +390,10 @@ public function getCountersOpRisks($mode = 'raw') } $countersRiskOP[$imax][$prob] += 1; - $distribRiskOp[$color] += 1; + ++$distribRiskOp[$color]; $riskOpMaxSum[$color] += $max; - if ($treatment !== 5) { + if ($operationalInstanceRisk->isTreated()) { if (!isset($byTreatment['treated'][$color]['count'])) { $byTreatment['treated'][$color]['count'] = 0; } @@ -454,77 +406,65 @@ public function getCountersOpRisks($mode = 'raw') $byTreatment['treated'][$color]['sum'] += $max; } - switch($treatment) { - case 1: - $kindOfTreatment = 'reduction'; - break; - case 2: - $kindOfTreatment = 'denied'; - break; - case 3: - $kindOfTreatment = 'accepted'; - break; - case 4: - $kindOfTreatment = 'shared'; - break; - case 5: - $kindOfTreatment = 'not_treated'; - break; - } + $kindOfMeasure = $operationalInstanceRisk->getTreatmentServiceName(); - if (!isset($byTreatment['all'][$kindOfTreatment]['count'])) { - $byTreatment['all'][$kindOfTreatment]['count'] = 0; + if (!isset($byTreatment['all'][$kindOfMeasure]['count'])) { + $byTreatment['all'][$kindOfMeasure]['count'] = 0; } - if (!isset($byTreatment['all'][$kindOfTreatment]['sum'])) { - $byTreatment['all'][$kindOfTreatment]['sum'] = 0; + if (!isset($byTreatment['all'][$kindOfMeasure]['sum'])) { + $byTreatment['all'][$kindOfMeasure]['sum'] = 0; } - if (!isset($byTreatment[$kindOfTreatment][$color]['count'])) { - $byTreatment[$kindOfTreatment][$color]['count'] = 0; + if (!isset($byTreatment[$kindOfMeasure][$color]['count'])) { + $byTreatment[$kindOfMeasure][$color]['count'] = 0; } - if (!isset($byTreatment[$kindOfTreatment][$color]['sum'])) { - $byTreatment[$kindOfTreatment][$color]['sum'] = 0; + if (!isset($byTreatment[$kindOfMeasure][$color]['sum'])) { + $byTreatment[$kindOfMeasure][$color]['sum'] = 0; } - $byTreatment[$kindOfTreatment][$color]['count'] += 1; - $byTreatment[$kindOfTreatment][$color]['sum'] += $max; + $byTreatment[$kindOfMeasure][$color]['count'] += 1; + $byTreatment[$kindOfMeasure][$color]['sum'] += $max; - $byTreatment['all'][$kindOfTreatment]['count'] += 1; - $byTreatment['all'][$kindOfTreatment]['sum'] += $max; + $byTreatment['all'][$kindOfMeasure]['count'] += 1; + $byTreatment['all'][$kindOfMeasure]['sum'] += $max; } return [$countersRiskOP, $distribRiskOp, $riskOpMaxSum, $byTreatment]; - } /** * Returns the cell color to display for the provided risk value - * @param int $val The risk value + * + * @param int|null $val The risk value + * * @return int|string 0, 1, 2 corresponding to low/med/hi risk color, or an empty string in case of invalid value */ - private function getColor($val,$kindOfRisk = 'riskInfo') + private function getColor(Entity\Anr $anr, ?int $val, string $riskType = 'riskInfo') { - // Provient de l'ancienne version, on ne remonte que les valeurs '' / 0 / 1 / 2, les couleurs seront traitées par le FE - if ($val == -1 || is_null($val)) { + // Provient de l'ancienne version, on ne remonte que les valeurs '' / 0 / 1 / 2, les couleurs seront traitées + // par le FE + if ($val === null || $val === -1) { return ''; } - if ($kindOfRisk == 'riskInfo') { - if ($val <= $this->anr->get('seuil1')) { - return 0; - } - if ($val <= $this->anr->get('seuil2')) { - return 1; - } - } else { - if ($val <= $this->anr->get('seuilRolf1')) { - return 0; - } - if ($val <= $this->anr->get('seuilRolf2')) { - return 1; - } + + if ($riskType === 'riskInfo') { + if ($val <= $anr->getSeuil1()) { + return 0; + } + if ($val <= $anr->getSeuil2()) { + return 1; + } + } elseif ($riskType === 'riskOp') { + if ($val <= $anr->getSeuilRolf1()) { + return 0; + } + if ($val <= $anr->getSeuilRolf2()) { + return 1; + } } + return 2; } } diff --git a/src/Service/AnrCartoRiskServiceFactory.php b/src/Service/AnrCartoRiskServiceFactory.php deleted file mode 100755 index bd23bcd4..00000000 --- a/src/Service/AnrCartoRiskServiceFactory.php +++ /dev/null @@ -1,30 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Scale', - 'table' => 'Monarc\FrontOffice\Model\Table\ScaleTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'instanceTable' => 'Monarc\FrontOffice\Model\Table\InstanceTable', - 'instanceRiskTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskTable', - 'instanceRiskOpTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskOpTable', - 'instanceConsequenceTable' => 'Monarc\FrontOffice\Model\Table\InstanceConsequenceTable', - 'operationalRiskScaleTable' => 'Monarc\FrontOffice\Model\Table\OperationalRiskScaleTable', - 'threatTable' => 'Monarc\FrontOffice\Model\Table\ThreatTable', - ]; -} diff --git a/src/Service/AnrCheckStartedService.php b/src/Service/AnrCheckStartedService.php deleted file mode 100755 index 415ba8e3..00000000 --- a/src/Service/AnrCheckStartedService.php +++ /dev/null @@ -1,76 +0,0 @@ -anrTable = $anrTable; - $this->modelTable = $modelTable; - $this->instanceRiskTable = $instanceRiskTable; - $this->instanceConsequenceTable = $instanceConsequenceTable; - $this->threatTable = $threatTable; - $this->operationalInstanceRiskScaleTable = $operationalInstanceRiskScaleTable; - } - - /** - * Returns whether or not the ANR sensitive values (scales values) can be changed safely. - * It is not possible to change the scales thresholds when: - * - It has been explicitly disabled in the model ANR - * - Risks have been evaluated - * - Consequences have been evaluated - * - Threats have been evaluated - */ - public function canChange(int $anrId): bool - { - $anr = $this->anrTable->findById($anrId); - - $isScalesEditable = true; - if ($anr->getModel()) { - $model = $this->modelTable->getEntity($anr->getModel()); - $isScalesEditable = $model->get('isScalesUpdatable'); - } - - return $isScalesEditable - && !$this->instanceRiskTable->started($anr->getId()) - && !$this->instanceConsequenceTable->started($anr->getId()) - && !$this->threatTable->started($anr->getId()) - && !$this->operationalInstanceRiskScaleTable->isRisksEvaluationStartedForAnr($anr); - } -} diff --git a/src/Service/AnrCoreService.php b/src/Service/AnrCoreService.php deleted file mode 100644 index 92b64743..00000000 --- a/src/Service/AnrCoreService.php +++ /dev/null @@ -1,11 +0,0 @@ - Table\AnrTable::class, - 'entity' => Anr::class, - 'scaleService' => AnrScaleService::class, - 'recordService' => AnrRecordService::class, - 'configService' => ConfigService::class, - 'instanceService' => AnrInstanceService::class, - 'anrObjectCategoryTable' => Table\AnrObjectCategoryTable::class, - 'instanceTable' => Table\InstanceTable::class, - 'instanceConsequenceTable' => Table\InstanceConsequenceTable::class, - 'instanceRiskTable' => Table\InstanceRiskTable::class, - 'instanceRiskOpTable' => Table\InstanceRiskOpTable::class, - 'MonarcObjectTable' => Table\MonarcObjectTable::class, - 'scaleTable' => Table\ScaleTable::class, - 'scaleImpactTypeTable' => Table\ScaleImpactTypeTable::class, - 'scaleCommentTable' => Table\ScaleCommentTable::class, - 'questionTable' => Table\QuestionTable::class, - 'questionChoiceTable' => Table\QuestionChoiceTable::class, - 'threatTable' => Table\ThreatTable::class, - 'interviewTable' => Table\InterviewTable::class, - 'deliveryTable' => Table\DeliveryTable::class, - 'referentialTable' => Table\ReferentialTable::class, - 'measureTable' => Table\MeasureTable::class, - 'measureMeasureTable' => Table\MeasureMeasureTable::class, - 'soaCategoryTable' => Table\SoaCategoryTable::class, - 'soaTable' => Table\SoaTable::class, - 'recordTable' => Table\RecordTable::class, - 'operationalRiskScalesExportService' => OperationalRiskScalesExportService::class, - 'anrMetadatasOnInstancesExportService' => AnrMetadatasOnInstancesExportService::class, - 'soaScaleCommentExportService' => SoaScaleCommentExportService::class, - ]; -} diff --git a/src/Service/AnrInstanceConsequenceService.php b/src/Service/AnrInstanceConsequenceService.php index 1cb22afd..13b51421 100644 --- a/src/Service/AnrInstanceConsequenceService.php +++ b/src/Service/AnrInstanceConsequenceService.php @@ -1,10 +1,236 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getConsequencesData(Entity\Instance $instance, bool $includeScaleComments = false): array + { + $result = []; + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); + foreach ($instance->getInstanceConsequences() as $instanceConsequence) { + $scaleImpactType = $instanceConsequence->getScaleImpactType(); + if (!$scaleImpactType->isHidden()) { + $consequenceData = [ + 'id' => $instanceConsequence->getId(), + 'scaleImpactTypeId' => $scaleImpactType->getId(), + 'scaleImpactType' => $scaleImpactType->getType(), + 'scaleImpactTypeDescription1' => $scaleImpactType->getLabel(1), + 'scaleImpactTypeDescription2' => $scaleImpactType->getLabel(2), + 'scaleImpactTypeDescription3' => $scaleImpactType->getLabel(3), + 'scaleImpactTypeDescription4' => $scaleImpactType->getLabel(4), + 'c_risk' => $instanceConsequence->getConfidentiality(), + 'i_risk' => $instanceConsequence->getIntegrity(), + 'd_risk' => $instanceConsequence->getAvailability(), + 'isHidden' => $instanceConsequence->isHidden(), + ]; + if ($includeScaleComments) { + $consequenceData['comments'] = []; + foreach ($scaleImpactType->getScaleComments() as $scaleComment) { + $consequenceData['comments'][$scaleComment->getScaleValue()] = $scaleComment + ->getComment($anr->getLanguage()); + } + } + + $result[] = $consequenceData; + } + } + + return $result; + } + + /** + * Creates the instance consequences based on a sibling instance's consequences or available scale impact types. + */ + public function createInstanceConsequences( + Entity\Instance $instance, + Entity\Anr $anr, + Entity\MonarcObject $object, + bool $saveInDb = true + ): void { + $siblingInstance = null; + if ($object->isScopeGlobal()) { + $siblingInstance = $this->instanceTable->findOneByAnrAndObjectExcludeInstance($anr, $object, $instance); + } + + if ($siblingInstance !== null) { + foreach ($siblingInstance->getInstanceConsequences() as $instanceConsequence) { + /** @var Entity\ScaleImpactType $scalesImpactType */ + $scalesImpactType = $instanceConsequence->getScaleImpactType(); + $this->createInstanceConsequence( + $instance, + $scalesImpactType, + $instanceConsequence->isHidden(), + [ + 'confidentiality' => $instanceConsequence->getConfidentiality(), + 'integrity' => $instanceConsequence->getIntegrity(), + 'availability' => $instanceConsequence->getAvailability(), + ] + ); + } + } else { + /** @var Entity\ScaleImpactType $scalesImpactType */ + foreach ($this->scalesCacheHelper->getCachedScaleImpactTypes($anr) as $scalesImpactType) { + if (!\in_array( + $scalesImpactType->getType(), + CoreEntity\ScaleImpactTypeSuperClass::getScaleImpactTypesCid(), + true + )) { + $this->createInstanceConsequence($instance, $scalesImpactType, $scalesImpactType->isHidden()); + } + } + } + + if ($saveInDb) { + $this->instanceConsequenceTable->flush(); + } + } + + public function createInstanceConsequence( + Entity\Instance $instance, + Entity\ScaleImpactType $scaleImpactType, + bool $isHidden = false, + array $evaluationCriteria = [], + bool $saveInTheDb = false + ): Entity\InstanceConsequence { + $instanceConsequence = (new Entity\InstanceConsequence()) + ->setAnr($instance->getAnr()) + ->setInstance($instance) + ->setScaleImpactType($scaleImpactType) + ->setIsHidden($isHidden) + ->setCreator($this->connectedUser->getEmail()); + if (!$isHidden && isset($evaluationCriteria['confidentiality'])) { + $instanceConsequence->setConfidentiality($evaluationCriteria['confidentiality']); + } + if (!$isHidden && isset($evaluationCriteria['integrity'])) { + $instanceConsequence->setIntegrity($evaluationCriteria['integrity']); + } + if (!$isHidden && isset($evaluationCriteria['availability'])) { + $instanceConsequence->setAvailability($evaluationCriteria['availability']); + } + + $this->instanceConsequenceTable->save($instanceConsequence, $saveInTheDb); + + return $instanceConsequence; + } + + /** + * This method is called from controllers to hide / show a specific consequence only linked to a specific instance. + * The other place is AnrInstanceService, to update an instance impacts. + */ + public function patchConsequence(Entity\Anr $anr, int $id, array $data): Entity\InstanceConsequence + { + /** @var Entity\InstanceConsequence $instanceConsequence */ + $instanceConsequence = $this->instanceConsequenceTable->findByIdAndAnr($id, $anr); + + $this->verifyImpacts( + $this->scalesCacheHelper->getCachedScaleByType($anr, CoreEntity\ScaleSuperClass::TYPE_IMPACT), + $data + ); + + $updateInstance = $instanceConsequence->isHidden() !== (bool)$data['isHidden']; + + $instanceConsequence + ->setIsHidden((bool)$data['isHidden']) + ->setUpdater($this->connectedUser->getEmail()); + if (isset($data['confidentiality'])) { + $updateInstance = $updateInstance + || $instanceConsequence->getConfidentiality() !== $data['confidentiality']; + $instanceConsequence->setConfidentiality($data['confidentiality']); + } + if (isset($data['integrity'])) { + $updateInstance = $updateInstance || $instanceConsequence->getIntegrity() !== $data['integrity']; + $instanceConsequence->setIntegrity($data['integrity']); + } + if (isset($data['availability'])) { + $updateInstance = $updateInstance || $instanceConsequence->getAvailability() !== $data['availability']; + $instanceConsequence->setAvailability($data['availability']); + } + + if ($updateInstance) { + /** @var Entity\Instance $instance */ + $instance = $instanceConsequence->getInstance(); + $this->anrInstanceService->refreshInstanceImpactAndUpdateRisks($instance); + } + + $this->updateSiblingsConsequences($instanceConsequence, $updateInstance); + + $this->instanceConsequenceTable->save($instanceConsequence); + + return $instanceConsequence; + } + + /** Updated the consequences visibility based on the scales impact types visibility update. */ + public function updateConsequencesByScaleImpactType(Entity\ScaleImpactType $scaleImpactType, bool $hide): void + { + $instancesConsequences = $this->instanceConsequenceTable->findByScaleImpactType($scaleImpactType); + foreach ($instancesConsequences as $instanceConsequence) { + $instanceConsequence->setIsHidden($hide)->setUpdater($this->connectedUser->getEmail()); + $this->instanceConsequenceTable->save($instanceConsequence, false); + } + $this->instanceConsequenceTable->flush(); + } + + /** + * Updates the consequences of the instances at the same level. + */ + private function updateSiblingsConsequences( + Entity\InstanceConsequence $instanceConsequence, + bool $updateInstance + ): void { + $object = $instanceConsequence->getInstance()->getObject(); + if ($object->isScopeGlobal()) { + $anr = $instanceConsequence->getInstance()->getAnr(); + $siblingInstances = $this->instanceTable->findByAnrAndObject($anr, $object); + + foreach ($siblingInstances as $siblingInstance) { + $siblingInstanceConsequences = $this->instanceConsequenceTable->findByAnrInstanceAndScaleImpactType( + $anr, + $siblingInstance, + $instanceConsequence->getScaleImpactType() + ); + + foreach ($siblingInstanceConsequences as $siblingInstanceConsequence) { + $siblingInstanceConsequence + ->setIsHidden($instanceConsequence->isHidden()) + ->setConfidentiality($instanceConsequence->getConfidentiality()) + ->setIntegrity($instanceConsequence->getIntegrity()) + ->setAvailability($instanceConsequence->getAvailability()); + + $this->instanceConsequenceTable->save($siblingInstanceConsequence, false); + } + + if ($updateInstance) { + $this->anrInstanceService->refreshInstanceImpactAndUpdateRisks($siblingInstance); + } + } + } + } } diff --git a/src/Service/AnrInstanceConsequenceServiceFactory.php b/src/Service/AnrInstanceConsequenceServiceFactory.php deleted file mode 100755 index 9d358c98..00000000 --- a/src/Service/AnrInstanceConsequenceServiceFactory.php +++ /dev/null @@ -1,41 +0,0 @@ - Table\InstanceConsequenceTable::class, - 'entity' => InstanceConsequence::class, - 'anrTable' => Table\AnrTable::class, - 'instanceTable' => Table\InstanceTable::class, - 'MonarcObjectTable' => Table\MonarcObjectTable::class, - 'scaleTable' => Table\ScaleTable::class, - 'scaleImpactTypeTable' => Table\ScaleImpactTypeTable::class, - 'scaleCommentTable' => Table\ScaleCommentTable::class, - ]; - - // TODO: A temporary solution to inject SharedEventManager. All the factories classes will be removed. - public function __invoke(ContainerInterface $container, $requestedName, array $options = null) - { - $objectObjectService = parent::__invoke($container, $requestedName, $options); - - $objectObjectService->setSharedManager($container->get('EventManager')->getSharedManager()); - - return $objectObjectService; - } -} diff --git a/src/Service/AnrInstanceMetadataFieldService.php b/src/Service/AnrInstanceMetadataFieldService.php new file mode 100644 index 00000000..f5f66619 --- /dev/null +++ b/src/Service/AnrInstanceMetadataFieldService.php @@ -0,0 +1,83 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): AnrInstanceMetadataField + { + $metadataFieldData = current($data); + + return $this->createAnrInstanceMetadataField( + $anr, + $metadataFieldData[$anr->getLanguageCode()], + isset($metadataFieldData['isDeletable']) ? (bool)$metadataFieldData['isDeletable'] : null, + $saveInDb + ); + } + + public function createAnrInstanceMetadataField( + Anr $anr, + string $label, + ?bool $isDeletable, + bool $saveInDb + ): AnrInstanceMetadataField { + $metadataField = (new AnrInstanceMetadataField()) + ->setLabel($label) + ->setAnr($anr) + ->setCreator($this->connectedUser->getEmail()); + if ($isDeletable !== null) { + $metadataField->setIsDeletable($isDeletable); + } + + $this->anrInstanceMetadataFieldTable->save($metadataField, $saveInDb); + + return $metadataField; + } + + public function update(Anr $anr, int $id, array $data): AnrInstanceMetadataField + { + /** @var AnrInstanceMetadataField $metadataField */ + $metadataField = $this->anrInstanceMetadataFieldTable->findByIdAndAnr($id, $anr); + if (!$metadataField->isDeletable()) { + throw new Exception('Predefined instance metadata fields can\'t be modified.', 412); + } + + $metadataField->setLabel($data[$anr->getLanguageCode()])->setUpdater($this->connectedUser->getEmail()); + + return $metadataField; + } + + public function delete(Anr $anr, int $id): void + { + /** @var AnrInstanceMetadataField $metadataField */ + $metadataField = $this->anrInstanceMetadataFieldTable->findByIdAndAnr($id, $anr); + if (!$metadataField->isDeletable()) { + throw new Exception('Predefined instance metadata fields can\'t be deleted.', 412); + } + + $this->anrInstanceMetadataFieldTable->remove($metadataField); + } +} diff --git a/src/Service/AnrInstanceRiskOpService.php b/src/Service/AnrInstanceRiskOpService.php index 15a73871..469b97f6 100644 --- a/src/Service/AnrInstanceRiskOpService.php +++ b/src/Service/AnrInstanceRiskOpService.php @@ -1,185 +1,73 @@ recommendationRiskTable = $recommendationRiskTable; - $this->rolfRiskTable = $rolfRiskTable; - $this->recommendationTable = $recommendationTable; + $this->connectedUser = $connectedUserService->getConnectedUser(); } - public function createSpecificRiskOp(array $data): int + public function getOperationalRisks(Entity\Anr $anr, int $instanceId = null, array $params = []): array { - $instance = $this->instanceTable->findById((int)$data['instance']); - $anr = $instance->getAnr(); - - if ((int)$data['source'] === 2) { - $rolfRisk = (new RolfRisk()) - ->setAnr($anr) - ->setCode((string)$data['code']) - ->setLabels(['label' . $anr->getLanguage() => $data['label']]) - ->setDescriptions(['description' . $anr->getLanguage() => $data['description'] ?? '']) - ->setCreator($this->connectedUser->getFirstname() . ' ' . $this->connectedUser->getLastname()); - $this->rolfRiskTable->saveEntity($rolfRisk, true); - } else { - $rolfRisk = $this->rolfRiskTable->findById((int)$data['risk']); - $operationalInstanceRisk = $this->instanceRiskOpTable->findByAnrInstanceAndRolfRisk( - $anr, - $instance, - $rolfRisk - ); - if ($operationalInstanceRisk !== null) { - throw new Exception("This risk already exists in this instance", 412); - } - } - - $operationalInstanceRisk = (new InstanceRiskOp()) - ->setAnr($anr) - ->setRolfRisk($rolfRisk) - ->setInstance($instance) - ->setObject($instance->getObject()) - ->setSpecific(1) - ->setRiskCacheCode($rolfRisk->getCode()) - ->setRiskCacheLabels([ - 'riskCacheLabel1' => $rolfRisk->getLabel(1), - 'riskCacheLabel2' => $rolfRisk->getLabel(2), - 'riskCacheLabel3' => $rolfRisk->getLabel(3), - 'riskCacheLabel4' => $rolfRisk->getLabel(4), - ]) - ->setRiskCacheDescriptions([ - 'riskCacheDescription1' => $rolfRisk->getDescription(1), - 'riskCacheDescription2' => $rolfRisk->getDescription(2), - 'riskCacheDescription3' => $rolfRisk->getDescription(3), - 'riskCacheDescription4' => $rolfRisk->getDescription(4), - ]) - ->setCreator($this->connectedUser->getFirstname() . ' ' . $this->connectedUser->getLastname()); - - $this->instanceRiskOpTable->saveEntity($operationalInstanceRisk, false); - - $operationalRiskScaleTypes = $this->operationalRiskScaleTypeTable->findByAnrAndScaleType( - $instance->getAnr(), - OperationalRiskScale::TYPE_IMPACT - ); - foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { - $operationalInstanceRiskScale = (new OperationalInstanceRiskScale()) - ->setAnr($anr) - ->setOperationalInstanceRisk($operationalInstanceRisk) - ->setOperationalRiskScaleType($operationalRiskScaleType) - ->setCreator($this->connectedUser->getEmail()); - $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); + $instancesIds = []; + if ($instanceId !== null) { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($instanceId, $anr); + $instancesIds = $instance->getSelfAndChildrenIds(); } - $this->instanceRiskOpTable->getDb()->flush(); - - return $operationalInstanceRisk->getId(); - } - - public function getOperationalRisks(int $anrId, int $instanceId = null, array $params = []): array - { - $instancesIds = $this->determineInstancesIdsFromParam($instanceId); - - $anr = $this->anrTable->findById($anrId); - $anrLanguage = $anr->getLanguage(); - $operationalInstanceRisks = $this->instanceRiskOpTable->findByAnrInstancesAndFilterParams( $anr, $instancesIds, $params ); + $anrLanguage = $anr->getLanguage(); $result = []; - $scaleTypesTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::OPERATIONAL_RISK_SCALE_TYPE, Translation::OPERATIONAL_RISK_SCALE_COMMENT], - $this->getAnrLanguageCode($anr) - ); foreach ($operationalInstanceRisks as $operationalInstanceRisk) { $recommendationUuids = []; foreach ($operationalInstanceRisk->getRecommendationRisks() as $recommendationRisk) { - if ($recommendationRisk->getRecommandation() !== null) { - $recommendationUuids[] = $recommendationRisk->getRecommandation()->getUuid(); + if ($recommendationRisk->getRecommendation() !== null) { + $recommendationUuids[] = $recommendationRisk->getRecommendation()->getUuid(); } } @@ -188,9 +76,7 @@ public function getOperationalRisks(int $anrId, int $instanceId = null, array $p $operationalRiskScaleType = $operationalInstanceRiskScale->getOperationalRiskScaleType(); $scalesData[$operationalRiskScaleType->getId()] = [ 'instanceRiskScaleId' => $operationalInstanceRiskScale->getId(), - 'label' => isset($scaleTypesTranslations[$operationalRiskScaleType->getLabelTranslationKey()]) - ? $scaleTypesTranslations[$operationalRiskScaleType->getLabelTranslationKey()]->getValue() - : '', + 'label' => $operationalRiskScaleType->getLabel(), 'netValue' => $operationalInstanceRiskScale->getNetValue(), 'brutValue' => $operationalInstanceRiskScale->getBrutValue(), 'targetedValue' => $operationalInstanceRiskScale->getTargetedValue(), @@ -200,9 +86,7 @@ public function getOperationalRisks(int $anrId, int $instanceId = null, array $p $result[] = [ 'id' => $operationalInstanceRisk->getId(), - 'rolfRisk' => $operationalInstanceRisk->getRolfRisk() - ? $operationalInstanceRisk->getRolfRisk()->getId() - : null, + 'rolfRisk' => $operationalInstanceRisk->getRolfRisk()?->getId(), 'label' . $anrLanguage => $operationalInstanceRisk->getRiskCacheLabel($anrLanguage), 'description' . $anrLanguage => $operationalInstanceRisk->getRiskCacheDescription($anrLanguage), 'context' => $operationalInstanceRisk->getContext(), @@ -219,12 +103,12 @@ public function getOperationalRisks(int $anrId, int $instanceId = null, array $p 'kindOfMeasure' => $operationalInstanceRisk->getKindOfMeasure(), 'comment' => $operationalInstanceRisk->getComment(), 'specific' => $operationalInstanceRisk->getSpecific(), - 't' => $operationalInstanceRisk->getKindOfMeasure() === InstanceRiskOp::KIND_NOT_TREATED ? 0 : 1, + 't' => $operationalInstanceRisk->isTreated(), 'position' => $operationalInstanceRisk->getInstance()->getPosition(), 'instanceInfos' => [ 'id' => $operationalInstanceRisk->getInstance()->getId(), 'scope' => $operationalInstanceRisk->getInstance()->getObject()->getScope(), - 'name' . $anrLanguage => $operationalInstanceRisk->getInstance()->{'getName' . $anrLanguage}(), + 'name' . $anrLanguage => $operationalInstanceRisk->getInstance()->getName($anrLanguage), ], 'recommendations' => implode(',', $recommendationUuids), ]; @@ -233,20 +117,248 @@ public function getOperationalRisks(int $anrId, int $instanceId = null, array $p return $result; } - public function getOperationalRisksInCsv(int $anrId, int $instanceId = null, array $params = []): string + public function createSpecificOperationalInstanceRisk(Entity\Anr $anr, array $data): Entity\InstanceRiskOp { - $instancesIds = $this->determineInstancesIdsFromParam($instanceId); - $anr = $this->anrTable->findById($anrId); - $anrLanguage = $anr->getLanguage(); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($data['instance'], $anr); + + if ($data['source'] === self::CREATION_SOURCE_NEW_RISK) { + $rolfRisk = (new Entity\RolfRisk()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels(['label' . $anr->getLanguage() => $data['label']]) + ->setDescriptions(['description' . $anr->getLanguage() => $data['description'] ?? '']) + ->setCreator($this->connectedUser->getFirstname() . ' ' . $this->connectedUser->getLastname()); + $this->rolfRiskTable->save($rolfRisk, true); + } else { + /** @var Entity\RolfRisk $rolfRisk */ + $rolfRisk = $this->rolfRiskTable->findById((int)$data['risk']); + $operationalInstanceRisk = $this->instanceRiskOpTable->findByAnrInstanceAndRolfRisk( + $anr, + $instance, + $rolfRisk + ); + if ($operationalInstanceRisk !== null) { + throw new Exception('This risk already exists in this instance', 412); + } + } + + $operationalInstanceRisk = (new Entity\InstanceRiskOp()) + ->setAnr($anr) + ->setRolfRisk($rolfRisk) + ->setInstance($instance) + ->setObject($instance->getObject()) + ->setIsSpecific(true) + ->setRiskCacheCode($rolfRisk->getCode()) + ->setRiskCacheLabels($rolfRisk->getLabels()) + ->setRiskCacheDescriptions($rolfRisk->getDescriptions()) + ->setCreator($this->connectedUser->getEmail()); $operationalRiskScaleTypes = $this->operationalRiskScaleTypeTable->findByAnrAndScaleType( - $anr, - OperationalRiskScale::TYPE_IMPACT + $instance->getAnr(), + CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT + ); + foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { + $operationalInstanceRiskScale = (new Entity\OperationalInstanceRiskScale()) + ->setAnr($anr) + ->setOperationalInstanceRisk($operationalInstanceRisk) + ->setOperationalRiskScaleType($operationalRiskScaleType) + ->setCreator($this->connectedUser->getEmail()); + $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); + } + + $this->instanceRiskOpTable->save($operationalInstanceRisk); + + return $operationalInstanceRisk; + } + + public function createInstanceRisksOp(Entity\Instance $instance, Entity\MonarcObject $monarcObject): void + { + if ($monarcObject->getRolfTag() === null || !$monarcObject->getAsset()->isPrimary()) { + return; + } + + foreach ($monarcObject->getRolfTag()->getRisks() as $rolfRisk) { + $this->createInstanceRiskOpWithScales($instance, $monarcObject, $rolfRisk); + } + + $this->instanceRiskOpTable->flush(); + } + + /** The objects are created and persisted but not saved in the DB. */ + public function createInstanceRiskOpWithScales( + Entity\Instance $instance, + Entity\MonarcObject $object, + Entity\RolfRisk $rolfRisk + ): Entity\InstanceRiskOp { + $instanceRiskOp = $this->createInstanceRiskOpObject($instance, $object, $rolfRisk); + + 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); + } + + return $instanceRiskOp; + } + + public function createInstanceRiskOpObject( + Entity\Instance $instance, + Entity\MonarcObject $object, + ?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 ? $rolfRisk->getCode() : $data['riskCacheCode']) + ->setRiskCacheLabels($rolfRisk ? [ + 'riskCacheLabel1' => $rolfRisk->getLabel(1), + 'riskCacheLabel2' => $rolfRisk->getLabel(2), + 'riskCacheLabel3' => $rolfRisk->getLabel(3), + 'riskCacheLabel4' => $rolfRisk->getLabel(4), + ] : ['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); + + return $instanceRiskOp; + } + + public function updateScaleValue(Entity\Anr $anr, int $id, array $data): Entity\InstanceRiskOp + { + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + $operationalInstanceRisk = $this->instanceRiskOpTable->findByIdAndAnr($id, $anr); + /** @var Entity\OperationalInstanceRiskScale $operationInstanceRiskScale */ + $operationInstanceRiskScale = $this->operationalInstanceRiskScaleTable->findByIdAndAnr( + (int)$data['instanceRiskScaleId'], + $anr ); - $scaleTypesTranslations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( + + if (isset($data['netValue']) && $operationInstanceRiskScale->getNetValue() !== (int)$data['netValue']) { + $this->verifyScaleValue($operationInstanceRiskScale, (int)$data['netValue']); + $operationInstanceRiskScale->setNetValue((int)$data['netValue']); + } + if (isset($data['brutValue']) && $operationInstanceRiskScale->getBrutValue() !== (int)$data['brutValue']) { + $this->verifyScaleValue($operationInstanceRiskScale, (int)$data['brutValue']); + $operationInstanceRiskScale->setBrutValue((int)$data['brutValue']); + } + if (isset($data['targetedValue']) + && $operationInstanceRiskScale->getTargetedValue() !== (int)$data['targetedValue'] + ) { + $this->verifyScaleValue($operationInstanceRiskScale, (int)$data['targetedValue']); + $operationInstanceRiskScale->setTargetedValue((int)$data['targetedValue']); + } + + $operationInstanceRiskScale->setUpdater($this->connectedUser->getEmail()); + + $this->updateRiskCacheValues($operationalInstanceRisk); + + $this->operationalInstanceRiskScaleTable->save($operationInstanceRiskScale); + + return $operationalInstanceRisk; + } + + public function update(Entity\Anr $anr, int $id, array $data): Entity\InstanceRiskOp + { + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + $operationalInstanceRisk = $this->instanceRiskOpTable->findByIdAndAnr($id, $anr); + + $likelihoodScale = $this->scalesCacheHelper->getCachedLikelihoodScale($anr); + if (isset($data['kindOfMeasure'])) { + $operationalInstanceRisk->setKindOfMeasure((int)$data['kindOfMeasure']); + } + if (isset($data['comment'])) { + $operationalInstanceRisk->setComment($data['comment']); + } + if (isset($data['netProb']) && $operationalInstanceRisk->getNetProb() !== $data['netProb']) { + $this->verifyScaleProbabilityValue((int)$data['netProb'], $likelihoodScale); + $operationalInstanceRisk->setNetProb((int)$data['netProb']); + } + if (isset($data['brutProb']) && $operationalInstanceRisk->getBrutProb() !== $data['brutProb']) { + $this->verifyScaleProbabilityValue((int)$data['brutProb'], $likelihoodScale); + $operationalInstanceRisk->setBrutProb((int)$data['brutProb']); + } + if (isset($data['targetedProb']) && $operationalInstanceRisk->getTargetedProb() !== $data['targetedProb']) { + $this->verifyScaleProbabilityValue((int)$data['targetedProb'], $likelihoodScale); + $operationalInstanceRisk->setTargetedProb((int)$data['targetedProb']); + } + if (isset($data['owner'])) { + $this->instanceRiskOwnerService->processRiskOwnerNameAndAssign( + (string)$data['owner'], + $operationalInstanceRisk + ); + } + if (isset($data['context']) && (string)$data['context'] !== $operationalInstanceRisk->getContext()) { + $operationalInstanceRisk->setContext($data['context']); + } + + $operationalInstanceRisk->setUpdater($this->connectedUser->getEmail()); + + $this->updateRiskCacheValues($operationalInstanceRisk); + + $this->instanceRiskOpTable->save($operationalInstanceRisk); + + $this->updateInstanceRiskRecommendationsPositions($operationalInstanceRisk); + + return $operationalInstanceRisk; + } + + public function updateRiskCacheValues(Entity\InstanceRiskOp $operationalInstanceRisk): void + { + foreach (['Brut', 'Net', 'Targeted'] as $valueType) { + $max = -1; + $probVal = $operationalInstanceRisk->{'get' . $valueType . 'Prob'}(); + if ($probVal !== -1) { + foreach ($operationalInstanceRisk->getOperationalInstanceRiskScales() as $riskScale) { + if (!$riskScale->getOperationalRiskScaleType()->isHidden()) { + $scaleValue = $riskScale->{'get' . $valueType . 'Value'}(); + if ($scaleValue > -1 && ($probVal * $scaleValue) > $max) { + $max = $probVal * $scaleValue; + } + } + } + } + + if ($operationalInstanceRisk->{'getCache' . $valueType . 'Risk'}() !== $max) { + $operationalInstanceRisk + ->setUpdater($this->connectedUser->getEmail()) + ->{'setCache' . $valueType . 'Risk'}($max); + $this->instanceRiskOpTable->save($operationalInstanceRisk, false); + } + } + } + + public function getOperationalRisksInCsv(Entity\Anr $anr, int $instanceId = null, array $params = []): string + { + $instancesIds = []; + if ($instanceId !== null) { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($instanceId, $anr); + $instancesIds = $instance->getSelfAndChildrenIds(); + } + $anrLanguage = $anr->getLanguage(); + + /** @var Entity\OperationalRiskScaleType[] $operationalRiskScaleTypes */ + $operationalRiskScaleTypes = $this->operationalRiskScaleTypeTable->findByAnrAndScaleType( $anr, - [Translation::OPERATIONAL_RISK_SCALE_TYPE], - $this->getAnrLanguageCode($anr) + CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT ); $tableHeaders = [ @@ -254,27 +366,25 @@ public function getOperationalRisksInCsv(int $anrId, int $instanceId = null, arr 'label' => $this->translateService->translate('Risk description', $anrLanguage), ]; - if ($anr->getShowRolfBrut() === 1) { + if ($anr->showRolfBrut()) { $translatedRiskValueDescription = $this->translateService->translate('Inherent risk', $anrLanguage); $tableHeaders['brutProb'] = $this->translateService->translate('Prob.', $anrLanguage) - . "(" . $translatedRiskValueDescription . ")"; + . '(' . $translatedRiskValueDescription . ')'; foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { - $label = $scaleTypesTranslations[$operationalRiskScaleType->getLabelTranslationKey()] - ->getValue(); - $tableHeaders[$label . " (" . $translatedRiskValueDescription . ")"] = $label . " (" - . $translatedRiskValueDescription . ")"; + $label = $operationalRiskScaleType->getLabel(); + $tableHeaders[$label . ' (' . $translatedRiskValueDescription . ')'] = $label . ' (' + . $translatedRiskValueDescription . ')'; } $tableHeaders['cacheBrutRisk'] = $translatedRiskValueDescription; } $translatedNetRiskDescription = $this->translateService->translate('Net risk', $anrLanguage); - $tableHeaders['netProb'] = $this->translateService->translate('Prob.', $anrLanguage) . "(" - . $translatedNetRiskDescription . ")"; + $tableHeaders['netProb'] = $this->translateService->translate('Prob.', $anrLanguage) . '(' + . $translatedNetRiskDescription . ')'; foreach ($operationalRiskScaleTypes as $operationalRiskScaleType) { - $label = $scaleTypesTranslations[$operationalRiskScaleType->getLabelTranslationKey()] - ->getValue(); - $tableHeaders[$label . " (" . $translatedNetRiskDescription . ")"] = $label . " (" - . $translatedNetRiskDescription . ")"; + $label = $operationalRiskScaleType->getLabel(); + $tableHeaders[$label . ' (' . $translatedNetRiskDescription . ')'] = $label . ' (' + . $translatedNetRiskDescription . ')'; } $tableHeaders['cacheNetRisk'] = $translatedNetRiskDescription; $tableHeaders['comment'] = $this->translateService->translate('Existing controls', $anrLanguage); @@ -297,10 +407,10 @@ public function getOperationalRisksInCsv(int $anrId, int $instanceId = null, arr ); foreach ($operationalInstanceRisks as $operationalInstanceRisk) { $values = [ - $operationalInstanceRisk->getInstance()->{'getName' . $anrLanguage}(), + $operationalInstanceRisk->getInstance()->getName($anrLanguage), $operationalInstanceRisk->getRiskCacheLabel($anrLanguage), ]; - if ($anr->getShowRolfBrut() === 1) { + if ($anr->showRolfBrut()) { $values[] = $operationalInstanceRisk->getBrutProb(); foreach ($operationalInstanceRisk->getOperationalInstanceRiskScales() as $instanceRiskScale) { $values[] = $instanceRiskScale->getBrutValue(); @@ -313,15 +423,15 @@ public function getOperationalRisksInCsv(int $anrId, int $instanceId = null, arr } $values[] = $operationalInstanceRisk->getCacheNetRisk(); $values[] = $operationalInstanceRisk->getComment(); - $values[] = InstanceRiskOp::getAvailableMeasureTypes()[$operationalInstanceRisk->getKindOfMeasure()]; - $values[] = $operationalInstanceRisk->getCacheTargetedRisk() == -1 ? - $operationalInstanceRisk->getCacheNetRisk() : - $operationalInstanceRisk->getCacheTargetedRisk(); - $values[] = $operationalInstanceRisk->getInstanceRiskOwner() !== null ? - $operationalInstanceRisk->getInstanceRiskOwner()->getName() : - null; + $values[] = CoreEntity\InstanceRiskOpSuperClass::getAvailableMeasureTypes()[ + $operationalInstanceRisk->getKindOfMeasure() + ]; + $values[] = $operationalInstanceRisk->getCacheTargetedRisk() === -1 + ? $operationalInstanceRisk->getCacheNetRisk() + : $operationalInstanceRisk->getCacheTargetedRisk(); + $values[] = $operationalInstanceRisk->getInstanceRiskOwner()?->getName(); $values[] = $operationalInstanceRisk->getContext(); - $values[] = $this->getCsvRecommendations($anr, $operationalInstanceRisk); + $values[] = $this->getCsvRecommendations($operationalInstanceRisk); $values[] = $this->getCsvMeasures($anrLanguage, $operationalInstanceRisk); @@ -335,149 +445,53 @@ public function getOperationalRisksInCsv(int $anrId, int $instanceId = null, arr return $output; } - /** - * @throws EntityNotFoundException - * @throws Exception - * @throws ORMException - */ - public function update(int $id, array $data): array + public function delete(Entity\Anr $anr, int $id): void { - $result = parent::update($id, $data); - - /** @var InstanceRiskOp $operationalInstanceRisk */ - $operationalInstanceRisk = $this->instanceRiskOpTable->findById($id); - - $this->updateInstanceRiskRecommendationsPositions($operationalInstanceRisk); - - return $result; - } - - /** - * @throws EntityNotFoundException - * @throws Exception - * @throws ORMException - * @throws OptimisticLockException - */ - public function deleteFromAnr(int $id, int $anrId): void - { - $operationalInstanceRisk = $this->instanceRiskOpTable->findById($id); + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + $operationalInstanceRisk = $this->instanceRiskOpTable->findByIdAndAnr($id, $anr); if (!$operationalInstanceRisk->isSpecific()) { throw new Exception('Only specific risks can be deleted.', 412); } - // TODO: implement Permissions validator and inject it here. similar to \Monarc\Core\Service\AbstractService::deleteFromAnr - - $this->instanceRiskOpTable->deleteEntity($operationalInstanceRisk); + $this->instanceRiskOpTable->remove($operationalInstanceRisk); $this->processRemovedInstanceRiskRecommendationsPositions($operationalInstanceRisk); } - /** - * Called from parent::createInstanceRiskOpWithScales - */ - protected function createInstanceRiskOpObjectFromInstanceObjectAndRolfRisk( - InstanceSuperClass $instance, - ObjectSuperClass $object, - RolfRiskSuperClass $rolfRisk - ): InstanceRiskOpSuperClass { - return (new InstanceRiskOp()) - ->setAnr($instance->getAnr()) - ->setInstance($instance) - ->setObject($object) - ->setRolfRisk($rolfRisk) - ->setRiskCacheCode($rolfRisk->getCode()) - ->setRiskCacheLabels([ - 'riskCacheLabel1' => $rolfRisk->getLabel(1), - 'riskCacheLabel2' => $rolfRisk->getLabel(2), - 'riskCacheLabel3' => $rolfRisk->getLabel(3), - 'riskCacheLabel4' => $rolfRisk->getLabel(4), - ]) - ->setRiskCacheDescriptions([ - 'riskCacheDescription1' => $rolfRisk->getDescription(1), - 'riskCacheDescription2' => $rolfRisk->getDescription(2), - 'riskCacheDescription3' => $rolfRisk->getDescription(3), - 'riskCacheDescription4' => $rolfRisk->getDescription(4), - ]); - } - - /** - * Called from InstanceRiskOpService::createInstanceRisksOp - * && OperationalRiskScaleService::createOperationalRiskScaleType - */ + /** The object is created and persisted, but not saved in the DB. */ public function createOperationalInstanceRiskScaleObject( - InstanceRiskOpSuperClass $instanceRiskOp, - OperationalRiskScaleTypeSuperClass $operationalRiskScaleType - ): OperationalInstanceRiskScaleSuperClass { - return (new OperationalInstanceRiskScale()) + Entity\InstanceRiskOp $instanceRiskOp, + Entity\OperationalRiskScaleType $operationalRiskScaleType + ): Entity\OperationalInstanceRiskScale { + $operationalInstanceRiskScale = (new Entity\OperationalInstanceRiskScale()) ->setAnr($instanceRiskOp->getAnr()) ->setOperationalInstanceRisk($instanceRiskOp) ->setOperationalRiskScaleType($operationalRiskScaleType) ->setCreator($this->connectedUser->getEmail()); - } - - protected function createInstanceRiskOwnerObject(AnrSuperClass $anr, string $ownerName): InstanceRiskOwnerSuperClass - { - return (new InstanceRiskOwner()) - ->setAnr($anr) - ->setName($ownerName) - ->setCreator($this->connectedUser->getEmail()); - } - - /** - * @param Instance[] $instances - * - * @return array - */ - private function extractInstancesAndTheirChildrenIds(array $instances): array - { - $instancesIds = []; - foreach ($instances as $instanceId => $instance) { - $instancesIds[] = $instanceId; - $instancesIds = array_merge( - $instancesIds, - $this->extractInstancesAndTheirChildrenIds($instance->getParameterValues('children')) - ); - } + $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); - return $instancesIds; + return $operationalInstanceRiskScale; } - private function determineInstancesIdsFromParam($instanceId): array + protected function getCsvRecommendations(Entity\InstanceRiskOp $operationalInstanceRisk): string { - $instancesIds = []; - if ($instanceId !== null) { - $instance = $this->instanceTable->findById($instanceId); - $this->instanceTable->initTree($instance); - $instancesIds = $this->extractInstancesAndTheirChildrenIds([$instance->getId() => $instance]); - } - - return $instancesIds; - } - - protected function getCsvRecommendations(AnrSuperClass $anr, InstanceRiskOp $operationalInstanceRisk): string - { - $recommendationsRisks = $this->recommendationRiskTable->findByAnrAndOperationalInstanceRisk( - $anr, - $operationalInstanceRisk - ); $csvData = []; - foreach ($recommendationsRisks as $recommendationRisk) { - $recommendation = $recommendationRisk->getRecommandation(); - $csvData[] = $recommendation->getCode() . " - " . $recommendation->getDescription(); + foreach ($operationalInstanceRisk->getRecommendationRisks() as $recommendationRisk) { + $recommendation = $recommendationRisk->getRecommendation(); + $csvData[] = $recommendation->getCode() . ' - ' . $recommendation->getDescription(); } return implode("\n", $csvData); } - protected function getCsvMeasures(int $anrLanguage, InstanceRiskOp $operationalInstanceRisk): string + protected function getCsvMeasures(int $anrLanguage, Entity\InstanceRiskOp $operationalInstanceRisk): string { - $measures = $operationalInstanceRisk->getRolfRisk() - ? $operationalInstanceRisk->getRolfRisk()->getMeasures() - : []; $csvData = []; - foreach ($measures as $measure) { - $csvData[] = "[" . $measure->getReferential()->{'getLabel' . $anrLanguage}() . "] " . - $measure->getCode() . " - " . $measure->{'getLabel' . $anrLanguage}(); + if ($operationalInstanceRisk->getRolfRisk() !== null) { + foreach ($operationalInstanceRisk->getRolfRisk()->getMeasures() as $measure) { + $csvData[] = '[' . $measure->getReferential()->getLabel($anrLanguage) . '] ' + . $measure->getCode() . ' - ' . $measure->getLabel($anrLanguage); + } } return implode("\n", $csvData); diff --git a/src/Service/AnrInstanceRiskService.php b/src/Service/AnrInstanceRiskService.php index d23ed702..28b5b21c 100644 --- a/src/Service/AnrInstanceRiskService.php +++ b/src/Service/AnrInstanceRiskService.php @@ -1,377 +1,506 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } - protected RecommandationRiskTable $recommendationRiskTable; + public function getInstanceRisks(Entity\Anr $anr, ?int $instanceId, array $params = []): array + { + if ($instanceId !== null) { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($instanceId, $anr); + $params['instanceIds'] = $instance->getSelfAndChildrenIds(); + } - protected TranslateService $translateService; + $languageIndex = $anr->getLanguage(); - public function updateFromRiskTable(int $instanceRiskId, array $data) - { - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('table'); - $instanceRisk = $instanceRiskTable->getEntity($instanceRiskId); + /** @var Entity\InstanceRisk[] $instanceRisks */ + $instanceRisks = $this->instanceRiskTable->findInstancesRisksByParams($anr, $languageIndex, $params); - //security - $data['specific'] = $instanceRisk->get('specific'); + $result = []; + foreach ($instanceRisks as $instanceRisk) { + $object = $instanceRisk->getInstance()->getObject(); + $threat = $instanceRisk->getThreat(); + $vulnerability = $instanceRisk->getVulnerability(); + $key = $object->isScopeGlobal() + ? 'o' . $object->getUuid() . '-' . $threat->getUuid() . '-' . $vulnerability->getUuid() + : 'r' . $instanceRisk->getId(); + if (!isset($result[$key]) || $this->areInstanceRiskImpactsHigher($instanceRisk, $result[$key])) { + $recommendationsUuids = []; + foreach ($instanceRisk->getRecommendationRisks() as $recommendationRisk) { + if ($recommendationRisk->getRecommendation() !== null) { + $recommendationsUuids[] = $recommendationRisk->getRecommendation()->getUuid(); + } + } + $measures = []; + if ($instanceRisk->getAmv() !== null) { + foreach ($instanceRisk->getAmv()->getMeasures() as $measure) { + $measures[] = [ + 'uuid' => $measure->getUuid(), + 'code' => $measure->getCode(), + 'label' . $languageIndex => $measure->getLabel($languageIndex), + 'referential' => [ + 'uuid' => $measure->getReferential()->getUuid(), + 'label' . $languageIndex => $measure->getReferential()->getLabel($languageIndex), + ], + ]; + } + } - if ($instanceRisk->threatRate != $data['threatRate']) { - $data['mh'] = 0; + $result[$key] = [ + 'id' => $instanceRisk->getId(), + 'oid' => $object->getUuid(), + 'instance' => $instanceRisk->getInstance()->getId(), + 'instanceName' . $languageIndex => $instanceRisk->getInstance()->getName($languageIndex), + 'amv' => $instanceRisk->getAmv()?->getUuid(), + 'asset' => $instanceRisk->getAsset()->getUuid(), + 'assetLabel' . $languageIndex => $instanceRisk->getAsset()->getLabel($languageIndex), + 'assetDescription' . $languageIndex => $instanceRisk->getAsset()->getDescription($languageIndex), + 'threat' => $threat->getUuid(), + 'threatCode' => $threat->getCode(), + 'threatLabel' . $languageIndex => $threat->getLabel($languageIndex), + 'threatDescription' . $languageIndex => $threat->getDescription($languageIndex), + 'threatRate' => $instanceRisk->getThreatRate(), + 'vulnerability' => $vulnerability->getUuid(), + 'vulnCode' => $vulnerability->getCode(), + 'vulnLabel' . $languageIndex => $vulnerability->getLabel($languageIndex), + 'vulnDescription' . $languageIndex => $vulnerability->getDescription($languageIndex), + 'vulnerabilityRate' => $instanceRisk->getVulnerabilityRate(), + 'specific' => $instanceRisk->getSpecific(), + 'reductionAmount' => $instanceRisk->getReductionAmount(), + 'c_impact' => $instanceRisk->getInstance()->getConfidentiality(), + 'c_risk' => $instanceRisk->getRiskConfidentiality(), + 'c_risk_enabled' => $threat->getConfidentiality(), + 'i_impact' => $instanceRisk->getInstance()->getIntegrity(), + 'i_risk' => $instanceRisk->getRiskIntegrity(), + 'i_risk_enabled' => $threat->getIntegrity(), + 'd_impact' => $instanceRisk->getInstance()->getAvailability(), + 'd_risk' => $instanceRisk->getRiskAvailability(), + 'd_risk_enabled' => $threat->getAvailability(), + 'target_risk' => $instanceRisk->getCacheTargetedRisk(), + 'max_risk' => $instanceRisk->getCacheMaxRisk(), + 'comment' => $instanceRisk->getComment(), + 'scope' => $object->getScope(), + 'kindOfMeasure' => $instanceRisk->getKindOfMeasure(), + 't' => $instanceRisk->isTreated(), + 'tid' => $threat->getUuid(), + 'vid' => $vulnerability->getUuid(), + 'context' => $instanceRisk->getContext(), + 'owner' => $instanceRisk->getInstanceRiskOwner() + ? $instanceRisk->getInstanceRiskOwner()->getName() + : '', + 'recommendations' => implode(',', $recommendationsUuids), + 'measures' => $measures, + ]; + } } - return $this->update($instanceRiskId, $data); + return array_values($result); } - /** - * @param int $id - * - * @return bool - * - * @throws EntityNotFoundException - * @throws ORMException - * @throws OptimisticLockException - */ - public function delete($id) - { - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('table'); - /** @var InstanceRisk $instanceRisk */ - $instanceRisk = $instanceRiskTable->findById($id); - - $instanceRiskTable->deleteEntity($instanceRisk); + public function createInstanceRisk( + Entity\Instance $instance, + ?Entity\Amv $amv, + ?Entity\InstanceRisk $fromInstanceRisk = null, + ?Entity\Threat $threat = null, + ?Entity\Vulnerability $vulnerability = null, + bool $saveInDb = false + ): Entity\InstanceRisk { + if ($fromInstanceRisk === null && $amv === null && $threat === null && $vulnerability === null) { + throw new \LogicException('Instance risk can\'t be created without threat and vulnerability.'); + } - $this->processRemovedInstanceRiskRecommendationsPositions($instanceRisk); + $instanceRisk = $fromInstanceRisk !== null + ? Entity\InstanceRisk::constructFromObjectOfTheSameAnr($fromInstanceRisk) + : new Entity\InstanceRisk(); - return true; - } + $instanceRisk + ->setInstance($instance) + ->setCreator($this->connectedUser->getEmail()); + if ($fromInstanceRisk === null) { + $instanceRisk + ->setAnr($instance->getAnr()) + ->setAmv($amv) + ->setAsset($amv !== null ? $amv->getAsset() : $instance->getAsset()) + ->setThreat($amv !== null ? $amv->getThreat() : $threat) + ->setVulnerability($amv !== null ? $amv->getVulnerability() : $vulnerability); + } else { + /* The evaluation values are only set when the object is created based on the other instance risk. */ + $this->recalculateRiskRates($instanceRisk); + } - public function updateRisks(InstanceRiskSuperClass $instanceRisk, bool $last = true): void - { - parent::updateRisks($instanceRisk, $last); + $this->instanceRiskTable->save($instanceRisk, $saveInDb); - $this->updateInstanceRiskRecommendationsPositions($instanceRisk); + return $instanceRisk; } - public function getInstanceRisksInCsv($anrId, $instanceId = null, $params = []): string - { - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - $anr = $anrTable->findById($anrId); - $anrLanguage = $anr->getLanguage(); + /** + * Is used when a new library object is instantiated to an ANR and during the import. + */ + public function createInstanceRisks( + Entity\Instance $instance, + Entity\MonarcObject $object, + array $params = [], + bool $saveInDb = true + ): void { + $siblingInstance = null; + if ($object->isScopeGlobal()) { + $siblingInstance = $this->instanceTable + ->findOneByAnrAndObjectExcludeInstance($instance->getAnr(), $object, $instance); + } - // Fill in the header - $output = implode(';', [ - $this->translateService->translate('Asset', $anrLanguage), - $this->translateService->translate('C Impact', $anrLanguage), - $this->translateService->translate('I Impact', $anrLanguage), - $this->translateService->translate('A Impact', $anrLanguage), - $this->translateService->translate('Threat', $anrLanguage), - $this->translateService->translate('Prob.', $anrLanguage), - $this->translateService->translate('Vulnerability', $anrLanguage), - $this->translateService->translate('Existing controls', $anrLanguage), - $this->translateService->translate('Qualif.', $anrLanguage), - $this->translateService->translate('Current risk', $anrLanguage). " C", - $this->translateService->translate('Current risk', $anrLanguage) . " I", - $this->translateService->translate('Current risk', $anrLanguage) . " " - . $this->translateService->translate('A', $anrLanguage), - $this->translateService->translate('Treatment', $anrLanguage), - $this->translateService->translate('Residual risk', $anrLanguage), - $this->translateService->translate('Risk owner', $anrLanguage), - $this->translateService->translate('Risk context', $anrLanguage), - $this->translateService->translate('Recommendations', $anrLanguage), - $this->translateService->translate('Security referentials', $anrLanguage), - ]) . "\n"; + if ($siblingInstance !== null) { + /* In case the object is global and another instance is already presented in the ANR, + the same risks have to be created (including possible specific ones). */ + foreach ($siblingInstance->getInstanceRisks() as $siblingInstanceRisk) { + /** @var Entity\Amv $amv */ + $amv = $siblingInstanceRisk->getAmv(); + $instanceRisk = $this->createInstanceRisk($instance, $amv, $siblingInstanceRisk, null, null, $saveInDb); - $instanceRisks = $this->getInstanceRisks($anrId, $instanceId, $params); + $this->duplicateRecommendationRisks($siblingInstanceRisk, $instanceRisk); + $this->updateInstanceRiskRecommendationsPositions($instanceRisk); + } + } else { + foreach ($object->getAsset()->getAmvs() as $amv) { + $instanceRisk = $this->createInstanceRisk($instance, $amv, null, null, null, $saveInDb); + + /* Process risk owner and context in case of import. */ + if (!empty($params['risks'])) { + $riskKey = array_search($amv->getUuid(), array_column($params['risks'], 'amv'), true); + if ($riskKey !== false) { + $instanceRiskData = array_values($params['risks'])[$riskKey]; + $instanceRisk->setContext($instanceRiskData['context'] ?? ''); + if (!empty($instanceRiskData['riskOwner'])) { + /** @var Entity\Anr $anr */ + $anr = $instance->getAnr(); + $instanceRiskOwner = $this->instanceRiskOwnerService->getOrCreateInstanceRiskOwner( + $anr, + $anr, + $instanceRiskData['riskOwner'] + ); + $instanceRisk->setInstanceRiskOwner($instanceRiskOwner); + } + } + } - // Fill in the content - foreach ($instanceRisks as $instanceRisk) { - $values = [ - $instanceRisk['instanceName' . $anrLanguage], - $instanceRisk['c_impact'] === -1 ? null : $instanceRisk['c_impact'], - $instanceRisk['i_impact'] === -1 ? null : $instanceRisk['i_impact'], - $instanceRisk['d_impact'] === -1 ? null : $instanceRisk['d_impact'], - $instanceRisk['threatLabel' . $anrLanguage], - $instanceRisk['threatRate'] === -1 ? null : $instanceRisk['threatRate'], - $instanceRisk['vulnLabel' . $anrLanguage], - $instanceRisk['comment'], - $instanceRisk['vulnerabilityRate'] === -1 ? null : $instanceRisk['vulnerabilityRate'], - $instanceRisk['c_risk_enabled'] === 0 || $instanceRisk['c_risk'] === -1 - ? null - : $instanceRisk['c_risk'], - $instanceRisk['i_risk_enabled'] === 0 || $instanceRisk['i_risk'] === -1 - ? null - : $instanceRisk['i_risk'], - $instanceRisk['d_risk_enabled'] === 0 || $instanceRisk['d_risk'] === -1 - ? null - : $instanceRisk['d_risk'], - $this->translateService->translate( - InstanceRisk::getAvailableMeasureTypes()[$instanceRisk['kindOfMeasure']], - $anrLanguage - ), - $instanceRisk['target_risk'] === -1 ? null : $instanceRisk['target_risk'], - $instanceRisk['owner'], - $instanceRisk['context'], - $this->getRecommendationsInCsv($anr, explode(",", (string)$instanceRisk['recommendations'])), - $instanceRisk['amv'] === null ? null : $this->getMeasuresInCsv($anr, $instanceRisk['amv']), - ]; - - $output .= '"'; - $search = ['"']; - $replace = ["'"]; - $output .= implode('";"', str_replace($search, $replace, $values)); - $output .= "\"\r\n"; + $this->instanceRiskTable->save($instanceRisk, false); + } } - return $output; + if ($saveInDb) { + $this->instanceRiskTable->flush(); + } } - /** - * TODO: review the logic. Moved from AnrRiskService. - */ - public function createInstanceRisk($data) + public function createSpecificInstanceRisk(Entity\Anr $anr, array $data): Entity\InstanceRisk { - $data['specific'] = 1; - - // Check that we don't already have a risk with this vuln/threat/instance combo - $instanceRisks = $this->getList(0, 1, null, null, [ - 'anr' => $data['anr'], - 'th.anr' => $data['anr'], - 'v.anr' => $data['anr'], - 'v.uuid' => $data['vulnerability']['uuid'], - 'th.uuid' => $data['threat']['uuid'], - 'i.id' => $data['instance'] - ]); - if (!empty($instanceRisks)) { - throw new Exception("This risk already exists in this instance", 412); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($data['instance'], $anr); + /** @var Entity\Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($data['threat'], $anr); + /** @var Entity\Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($data['vulnerability'], $anr); + + if ($this->instanceRiskTable + ->existsInAnrWithInstanceThreatAndVulnerability($instance, $threat, $vulnerability) + ) { + throw new Exception('This risk already exists in this instance', 412); } - $instanceRisk = new InstanceRisk(); - $instanceRisk->setLanguage($this->getLanguage()); - $instanceRisk->setDbAdapter($this->get('table')->getDb()); + $instanceRisk = (new Entity\InstanceRisk()) + ->setAnr($anr) + ->setInstance($instance) + ->setAsset($instance->getAsset()) + ->setThreat($threat) + ->setVulnerability($vulnerability) + ->setSpecific(CoreEntity\InstanceRiskSuperClass::TYPE_SPECIFIC) + ->setCreator($this->connectedUser->getEmail()); + + if ($instance->getObject()->isScopeGlobal()) { + /* Creates the same specific instance risk inside sibling instances based on the global object. */ + $siblingGlobalInstances = $this->instanceTable->findGlobalSiblingsByAnrAndInstance($anr, $instance); + foreach ($siblingGlobalInstances as $siblingGlobalInstance) { + $this->instanceRiskTable->save( + Entity\InstanceRisk::constructFromObjectOfTheSameAnr($instanceRisk) + ->setInstance($siblingGlobalInstance) + ->setCreator($this->connectedUser->getEmail()), + false + ); + } + } - /** @var InstanceTable $instanceTable */ - $instanceTable = $this->get('instanceTable'); - $instance = $instanceTable->getEntity($data['instance']); - $data['asset'] = ['uuid' => $instance->getAsset()->getUuid(), 'anr' => $data['anr']]; - $instanceRisk->exchangeArray($data); - $dependencies = property_exists($this, 'dependencies') ? $this->dependencies : []; - $this->setDependencies($instanceRisk, $dependencies); + $this->instanceRiskTable->save($instanceRisk); - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('table'); - $instanceRiskTable->saveEntity($instanceRisk); + return $instanceRisk; + } - //if global object, save risk of all instance of global object for this anr - if ($instanceRisk->getInstance()->getObject()->isScopeGlobal()) { - $brothers = $instanceTable->getEntityByFields([ - 'anr' => $instanceRisk->getAnr()->getId(), - 'object' => [ - 'anr' => $instanceRisk->getAnr()->getId(), - 'uuid' => $instanceRisk->getInstance()->getObject()->getUuid() - ], - 'id' => [ - 'op' => '!=', - 'value' => $instance->getId(), - ] - ]); - $i = 1; - $nbBrothers = \count($brothers); - foreach ($brothers as $brother) { - $newRisk = clone $instanceRisk; - $newRisk->setInstance($brother); - $instanceRiskTable->saveEntity($newRisk, $i === $nbBrothers); - $i++; + public function update( + Entity\Anr $anr, + int $id, + array $data, + bool $manageGlobal = true + ): Entity\InstanceRisk { + /** @var Entity\InstanceRisk $instanceRisk */ + $instanceRisk = $this->instanceRiskTable->findByIdAndAnr($id, $anr); + + $this->verifyInstanceRiskRates($instanceRisk, $this->scaleTable, $data); + + $this->updateInstanceRiskData($instanceRisk, $data); + + if ($manageGlobal) { + /* The impact has to be updated for the siblings / other global instances and risks. */ + $object = $instanceRisk->getInstance()->getObject(); + if ($object->isScopeGlobal()) { + $instances = $this->instanceTable->findByAnrAndObject($instanceRisk->getAnr(), $object); + + foreach ($instances as $instance) { + if ($instanceRisk->getInstance()->getId() === $instance->getId()) { + continue; + } + + $siblingInstancesRisks = $this->instanceRiskTable->findByInstanceAndInstanceRiskRelations( + $instance, + $instanceRisk + ); + + foreach ($siblingInstancesRisks as $siblingInstanceRisk) { + $this->updateInstanceRiskData($siblingInstanceRisk, $data); + } + } } } - return $instanceRisk->getId(); + $this->instanceRiskTable->save($instanceRisk); + + return $instanceRisk; } - /** - * TODO: review the logic, probably can be merged with self::delete. Moved from AnrRiskService. - */ - public function deleteInstanceRisk(int $id, int $anrId) + public function delete(Entity\Anr $anr, int $id): void { - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('table'); - $instanceRisk = $instanceRiskTable->findById($id); + /** @var Entity\InstanceRisk $instanceRisk */ + $instanceRisk = $this->instanceRiskTable->findByIdAndAnr($id, $anr); if (!$instanceRisk->isSpecific()) { throw new Exception('You can not delete a not specific risk', 412); } - if ($instanceRisk->getAnr()->getId() !== $anrId) { - throw new Exception('Anr id error', 412); - } - - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $this->get('userAnrTable'); - $userAnr = $userAnrTable->findByAnrAndUser($instanceRisk->getAnr(), $instanceRiskTable->getConnectedUser()); - if ($userAnr === null || $userAnr->getRwd() === 0) { - throw new Exception('You are not authorized to do this action', 412); - } - - // If the object is global, delete all risks link to brothers instances + /* If the object is global, delete all risks linked to sibling instances. */ if ($instanceRisk->getInstance()->getObject()->isScopeGlobal()) { - // Retrieve brothers - /** @var InstanceTable $instanceTable */ - $instanceTable = $this->get('instanceTable'); - /** @var Instance[] $brothers */ - $brothers = $instanceTable->getEntityByFields([ - 'anr' => $instanceRisk->getAnr()->getId(), - 'object' => [ - 'anr' => $instanceRisk->getAnr()->getId(), - 'uuid' => $instanceRisk->getInstance()->getObject()->getUuid(), - ], - ]); - - // Retrieve instances with same risk - $instancesRisks = $instanceRiskTable->getEntityByFields([ - 'asset' => [ - 'uuid' => $instanceRisk->getAsset()->getUuid(), - 'anr' => $instanceRisk->getAnr()->getId(), - ], - 'threat' => [ - 'uuid' => $instanceRisk->getThreat()->getUuid(), - 'anr' => $instanceRisk->getAnr()->getId(), - ], - 'vulnerability' => [ - 'uuid' => $instanceRisk->getVulnerability()->getUuid(), - 'anr' => $instanceRisk->getAnr()->getId(), - ], - ]); - - foreach ($instancesRisks as $instanceRisk) { - foreach ($brothers as $brother) { - if ($brother->getId() === $instanceRisk->getInstance()->getId() && $instanceRisk->getId() !== $id) { - $instanceRiskTable->deleteEntity($instanceRisk, false); - } - } - } - foreach ($instancesRisks as $siblingInstanceRisk) { - foreach ($brothers as $brother) { - if ($siblingInstanceRisk->getId() !== $id - && $brother->getId() === $siblingInstanceRisk->getInstance()->getId() - ) { - $instanceRiskTable->deleteEntity($siblingInstanceRisk, false); - } - } + $siblingInstanceRisks = $this->instanceRiskTable->findSiblingSpecificInstanceRisks($instanceRisk); + foreach ($siblingInstanceRisks as $siblingInstanceRisk) { + $this->instanceRiskTable->remove($siblingInstanceRisk, false); } } - $instanceRiskTable->deleteEntity($instanceRisk); + $this->instanceRiskTable->remove($instanceRisk); $this->processRemovedInstanceRiskRecommendationsPositions($instanceRisk); - - return true; - } - - protected function duplicateRecommendationRisk( - InstanceRiskSuperClass $instanceRisk, - InstanceRiskSuperClass $newInstanceRisk - ): void { - $recommendationRisks = $this->recommendationRiskTable->findByAnrAndInstanceRisk( - $newInstanceRisk->getAnr(), - $instanceRisk - ); - foreach ($recommendationRisks as $recommandationRisk) { - $newRecommendationRisk = (clone $recommandationRisk) - ->setId(null) - ->setInstance($newInstanceRisk->getInstance()) - ->setInstanceRisk($newInstanceRisk); - - $this->recommendationRiskTable->saveEntity($newRecommendationRisk, false); - } } - protected function createInstanceRiskOwnerObject(AnrSuperClass $anr, string $ownerName): InstanceRiskOwnerSuperClass + public function recalculateRiskRatesAndUpdateRecommendationsPositions(Entity\InstanceRisk $instanceRisk): void { - return (new InstanceRiskOwner()) - ->setAnr($anr) - ->setName($ownerName) - ->setCreator($this->getConnectedUser()->getEmail()); + $this->recalculateRiskRates($instanceRisk); + + $this->updateInstanceRiskRecommendationsPositions($instanceRisk); } - protected function getLanguageIndex(AnrSuperClass $anr): int + public function getInstanceRisksInCsv(Entity\Anr $anr, int $instanceId = null, array $params = []): string { - return $anr->getLanguage(); - } + $languageIndex = $anr->getLanguage(); - /** - * @param InstanceRisk $instanceRisk - * @param array $instanceRiskResult - * - * @return array - */ - protected function addCustomFieldsToInstanceRiskResult( - InstanceRiskSuperClass $instanceRisk, - array $instanceRiskResult - ): array { - $recommendationsUuids = []; - foreach ($instanceRisk->getRecommendationRisks() as $recommendationRisk) { - if ($recommendationRisk->getRecommandation() !== null) { - $recommendationsUuids[] = $recommendationRisk->getRecommandation()->getUuid(); - } + // Fill in the header + $output = implode(';', [ + $this->translateService->translate('Asset', $languageIndex), + $this->translateService->translate('C Impact', $languageIndex), + $this->translateService->translate('I Impact', $languageIndex), + $this->translateService->translate('A Impact', $languageIndex), + $this->translateService->translate('Threat', $languageIndex), + $this->translateService->translate('Prob.', $languageIndex), + $this->translateService->translate('Vulnerability', $languageIndex), + $this->translateService->translate('Existing controls', $languageIndex), + $this->translateService->translate('Qualif.', $languageIndex), + $this->translateService->translate('Current risk', $languageIndex). ' C', + $this->translateService->translate('Current risk', $languageIndex) . ' I', + $this->translateService->translate('Current risk', $languageIndex) . ' ' + . $this->translateService->translate('A', $languageIndex), + $this->translateService->translate('Treatment', $languageIndex), + $this->translateService->translate('Residual risk', $languageIndex), + $this->translateService->translate('Risk owner', $languageIndex), + $this->translateService->translate('Risk context', $languageIndex), + $this->translateService->translate('Recommendations', $languageIndex), + $this->translateService->translate('Security referentials', $languageIndex), + ]) . "\n"; + + if ($instanceId !== null) { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($instanceId, $anr); + $params['instanceIds'] = $instance->getSelfAndChildrenIds(); } - return array_merge( - $instanceRiskResult, - ['recommendations' => implode(',', $recommendationsUuids)] - ); - } + /** @var Entity\InstanceRisk[] $instanceRisks */ + $instanceRisks = $this->instanceRiskTable->findInstancesRisksByParams($anr, $languageIndex, $params); - private function getRecommendationsInCsv(AnrSuperClass $anr, array $recsUuids): string - { - $csvData = []; - foreach ($recsUuids as $recUuid) { - if (!empty($recUuid)) { - $recommendation = $this->recommendationTable->findByAnrAndUuid($anr, $recUuid); - $csvData[] = $recommendation->getCode() . " - " . $recommendation->getDescription(); + $impactValues = []; + foreach ($instanceRisks as $instanceRisk) { + $instance = $instanceRisk->getInstance(); + $object = $instance->getObject(); + $threat = $instanceRisk->getThreat(); + $vulnerability = $instanceRisk->getVulnerability(); + $key = $object->isScopeGlobal() + ? 'o' . $object->getUuid() . '-' . $threat->getUuid() . '-' . $vulnerability->getUuid() + : 'r' . $instanceRisk->getId(); + if (!isset($values[$key]) || $this->areInstanceRiskImpactsHigher($instanceRisk, $impactValues[$key])) { + $recommendationData = []; + foreach ($instanceRisk->getRecommendationRisks() as $recommendationRisk) { + $recommendationData[] = $recommendationRisk->getRecommendation()->getCode() + . ' - ' . $recommendationRisk->getRecommendation()->getDescription(); + } + $measuresData = []; + if ($instanceRisk->getAmv() !== null) { + foreach ($instanceRisk->getAmv()->getMeasures() as $measure) { + $measuresData[] = '[' . $measure->getReferential()->getLabel($anr->getLanguage()) . '] ' + . $measure->getCode() . ' - ' . $measure->getLabel($anr->getLanguage()); + } + } + + $impactValues[$key] = [ + 'max_risk' => $instanceRisk->getCacheMaxRisk(), + 'c_impact' => $instance->getConfidentiality(), + 'i_impact' => $instance->getIntegrity(), + 'd_impact' => $instance->getAvailability(), + ]; + + $values[$key] = [ + $instance->getName($languageIndex), + $instance->getConfidentiality() === -1 ? null : $instance->getConfidentiality(), + $instance->getIntegrity() === -1 ? null : $instance->getIntegrity(), + $instance->getAvailability() === -1 ? null : $instance->getAvailability(), + $threat->getLabel($languageIndex), + $instanceRisk->getThreatRate() === -1 ? null : $instanceRisk->getThreatRate(), + $vulnerability->getLabel($languageIndex), + $instanceRisk->getComment(), + $instanceRisk->getVulnerabilityRate() === -1 ? null : $instanceRisk->getVulnerabilityRate(), + $threat->getConfidentiality() === 0 || $instanceRisk->getRiskConfidentiality() === -1 + ? null + : $instanceRisk->getRiskConfidentiality(), + $instanceRisk->getThreat()->getIntegrity() === 0 || $instanceRisk->getRiskIntegrity() === -1 + ? null + : $instanceRisk->getRiskIntegrity(), + $instanceRisk->getThreat()->getAvailability() === 0 || $instanceRisk->getRiskAvailability() === -1 + ? null + : $instanceRisk->getRiskAvailability(), + $this->translateService->translate( + Entity\InstanceRisk::getAvailableMeasureTypes()[$instanceRisk->getKindOfMeasure()], + $languageIndex + ), + $instanceRisk->getCacheTargetedRisk() === -1 ? null : $instanceRisk->getCacheTargetedRisk(), + $instanceRisk->getInstanceRiskOwner() ? $instanceRisk->getInstanceRiskOwner()->getName() : '', + $instanceRisk->getContext(), + implode("\n", $recommendationData), + implode("\n", $measuresData), + ]; + + $output .= '"'; + $search = ['"']; + $replace = ["'"]; + $output .= implode('";"', str_replace($search, $replace, $values[$key])); + $output .= "\"\r\n"; } } - return implode("\n", $csvData); + return $output; } - private function getMeasuresInCsv(AnrSuperClass $anr, string $amvUuid): string + private function updateInstanceRiskData(Entity\InstanceRisk $instanceRisk, array $data): void { - /** @var AmvTable $amvTable */ - $amvTable = $this->get('amvTable'); - $amv = $amvTable->findByUuidAndAnrId($amvUuid, $anr->getId()); - $csvData = []; - foreach ($amv->getMeasures() as $measure) { - $csvData[] = "[" . $measure->getReferential()->{'getLabel' . $anr->getLanguage()}() . "] " - . $measure->getCode() . " - " . $measure->{'getLabel' . $anr->getLanguage()}(); + if (isset($data['owner'])) { + $this->instanceRiskOwnerService->processRiskOwnerNameAndAssign((string)$data['owner'], $instanceRisk); + } + if (isset($data['context'])) { + $instanceRisk->setContext($data['context']); + } + if (isset($data['reductionAmount'])) { + $instanceRisk->setReductionAmount((int)$data['reductionAmount']); + } + if (isset($data['threatRate']) && $instanceRisk->getThreatRate() !== $data['threatRate']) { + $instanceRisk->setThreatRate((int)$data['threatRate']) + ->setIsThreatRateNotSetOrModifiedExternally(false); + } + if (isset($data['vulnerabilityRate'])) { + $instanceRisk->setVulnerabilityRate((int)$data['vulnerabilityRate']); + } + if (isset($data['comment'])) { + $instanceRisk->setComment($data['comment']); } + if (isset($data['kindOfMeasure'])) { + $instanceRisk->setKindOfMeasure((int)$data['kindOfMeasure']); + } + + $instanceRisk->setUpdater($this->connectedUser->getEmail()); + + $this->recalculateRiskRatesAndUpdateRecommendationsPositions($instanceRisk); + } - return implode("\n", $csvData); + private function duplicateRecommendationRisks( + Entity\InstanceRisk $fromInstanceRisk, + Entity\InstanceRisk $newInstanceRisk + ): void { + /** @var Entity\Anr $anr */ + $anr = $newInstanceRisk->getAnr(); + /** @var Entity\Instance $instance */ + $instance = $newInstanceRisk->getInstance(); + foreach ($fromInstanceRisk->getRecommendationRisks() as $recommendationRiskToDuplicate) { + $newRecommendationRisk = (new Entity\RecommendationRisk()) + ->setAnr($anr) + ->setCommentAfter($recommendationRiskToDuplicate->getCommentAfter()) + ->setRecommendation($recommendationRiskToDuplicate->getRecommendation()) + ->setInstance($instance) + ->setInstanceRisk($newInstanceRisk) + ->setGlobalObject($recommendationRiskToDuplicate->getGlobalObject()) + ->setAsset($recommendationRiskToDuplicate->getAsset()) + ->setThreat($recommendationRiskToDuplicate->getThreat()) + ->setVulnerability($recommendationRiskToDuplicate->getVulnerability()); + + $this->recommendationRiskTable->save($newRecommendationRisk, false); + } } } diff --git a/src/Service/AnrInstanceRiskServiceFactory.php b/src/Service/AnrInstanceRiskServiceFactory.php deleted file mode 100755 index 2e1cf779..00000000 --- a/src/Service/AnrInstanceRiskServiceFactory.php +++ /dev/null @@ -1,40 +0,0 @@ - Table\InstanceRiskTable::class, - 'entity' => InstanceRisk::class, - 'amvTable' => Table\AmvTable::class, - 'anrTable' => Table\AnrTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'assetTable' => Table\AssetTable::class, - 'instanceTable' => Table\InstanceTable::class, - 'instanceRiskOwnerTable' => Table\InstanceRiskOwnerTable::class, - 'monarcObjectTable' => Table\MonarcObjectTable::class, - 'scaleTable' => Table\ScaleTable::class, - 'threatTable' => Table\ThreatTable::class, - 'vulnerabilityTable' => Table\VulnerabilityTable::class, - 'recommendationTable' => Table\RecommandationTable::class, - 'recommendationRiskTable' => Table\RecommandationRiskTable::class, - 'translateService' => TranslateService::class, - ]; -} diff --git a/src/Service/AnrInstanceService.php b/src/Service/AnrInstanceService.php index 01082254..3f02dbfa 100755 --- a/src/Service/AnrInstanceService.php +++ b/src/Service/AnrInstanceService.php @@ -1,63 +1,252 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getInstancesData(Entity\Anr $anr): array + { + /** @var Entity\Instance[] $rootInstances */ + $rootInstances = $this->instanceTable->findRootInstancesByAnrAndOrderByPosition($anr); + $instanceData = []; + foreach ($rootInstances as $rootInstance) { + $instanceData[] = array_merge( + $this->getPreparedInstanceData($rootInstance), + ['child' => $this->getChildrenTreeList($rootInstance)] + ); + } + + return $instanceData; + } + + public function getInstanceData(Entity\Anr $anr, int $id): array + { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($id, $anr); + + $instanceData = $this->getPreparedInstanceData($instance); + $instanceData['consequences'] = $this->anrInstanceConsequenceService->getConsequencesData($instance); + $instanceData['instances'] = $this->getOtherInstances($instance); + + return $instanceData; + } + + public function instantiateObjectToAnr(Entity\Anr $anr, array $data, bool $isRootLevel = false): Entity\Instance + { + $instance = $this->createInstance($anr, $data, $isRootLevel); + + $this->createInstanceMetadataFromGlobalSibling($instance); + + /** @var Entity\MonarcObject $object */ + $object = $instance->getObject(); + $this->anrInstanceConsequenceService->createInstanceConsequences($instance, $anr, $object, false); + $instance->updateImpactBasedOnConsequences()->refreshInheritedImpact(); + + $this->instanceTable->save($instance, false); + + $this->anrInstanceRiskService->createInstanceRisks($instance, $object); + + $this->anrInstanceRiskOpService->createInstanceRisksOp($instance, $object); + + /* Check if the root element is not the same as current child element to avoid a circular dependency. */ + if ($instance->isRoot() + || !$instance->hasParent() + || $instance->getParent()->isRoot() + || $instance->getParent()->getRoot()->getObject()->getUuid() !== $instance->getObject()->getUuid() + ) { + $this->createChildren($instance); + } + + return $instance; + } + + public function createInstance( + Entity\Anr $anr, + array $data, + bool $isRootLevel, + bool $saveInDb = true + ): Entity\Instance { + /** @var Entity\MonarcObject $object */ + $object = $data['object'] instanceof Entity\MonarcObject + ? $data['object'] + : $this->monarcObjectTable->findByUuidAndAnr($data['object'], $anr); + + $instance = (new Entity\Instance) + ->setAnr($anr) + ->setObject($object) + ->setAsset($object->getAsset()) + ->setNames($object->getNames()) + ->setLabels($object->getLabels()) + ->setCreator($this->connectedUser->getEmail()); + if (isset($data['confidentiality'])) { + $instance->setConfidentiality($data['confidentiality']); + } + if (isset($data['integrity'])) { + $instance->setIntegrity($data['integrity']); + } + if (isset($data['availability'])) { + $instance->setAvailability($data['availability']); + } + if (isset($data['isConfidentialityInherited'])) { + $instance->setInheritedConfidentiality($data['isConfidentialityInherited']); + } + if (isset($data['isIntegrityInherited'])) { + $instance->setInheritedIntegrity($data['isIntegrityInherited']); + } + if (isset($data['isAvailabilityInherited'])) { + $instance->setInheritedAvailability($data['isAvailabilityInherited']); + } + + if (!empty($data['parent'])) { + /** @var Entity\Instance $parentInstance */ + $parentInstance = $data['parent'] instanceof Entity\Instance + ? $data['parent'] + : $this->instanceTable->findByIdAndAnr($data['parent'], $anr); + + $instance->setParent($parentInstance)->setRoot($parentInstance->getRootInstance()); + } + + if (!$isRootLevel && isset($data['level'])) { + $instance->setLevel($data['level']); + } else { + $this->updateInstanceLevels($isRootLevel, $instance); + } + + $this->updatePositions( + $instance, + $this->instanceTable, + $this->getPreparedPositionData($this->instanceTable, $instance, $data) + ); + + $this->instanceTable->save($instance, $saveInDb); + + return $instance; + } + + public function updateInstance(Entity\Anr $anr, int $id, array $data): Entity\Instance + { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($id, $anr); + + $this->updateConsequences($anr, $data['consequences']); + + $this->refreshInstanceImpactAndUpdateRisks($instance); + + $this->updateOtherGlobalInstancesConsequences($instance); + + $this->instanceTable->save($instance); + + return $instance; + } + + public function patchInstance(Entity\Anr $anr, int $id, array $data): Entity\Instance + { + if (!empty($data['parent']) && $id === $data['parent']) { + throw new Exception('Instance can not be a parent of itself.', 412); + } + + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($id, $anr); + + $this->updateInstanceParent($instance, $data); + + $this->updatePositions( + $instance, + $this->instanceTable, + $this->getPreparedPositionData($this->instanceTable, $instance, $data) + ); + + $instance->refreshInheritedImpact(); - /** @var UserAnrTable */ - protected $userAnrTable; - protected $themeTable; - protected $instanceRiskTable; - protected $instanceRiskOpTable; + $this->updateRisks($instance); - /** @var RecommandationRiskTable */ - protected $recommendationRiskTable; + $this->updateChildrenImpactsAndRisks($instance); - /** @var RecommandationTable */ - protected $recommendationTable; + $this->instanceTable->save($instance->setUpdater($this->connectedUser->getEmail())); - /** @var RecommandationSetTable */ - protected $recommendationSetTable; + $this->updateOtherGlobalInstancesConsequences($instance); - /** @var TranslationTable */ - protected $translationTable; - protected $instanceMetadataTable; + return $instance; + } - public function delete($id) + public function updateChildrenImpactsAndRisks(Entity\Instance $instance): void { - /** @var InstanceTable $instanceTable */ - $instanceTable = $this->get('table'); - $anr = $instanceTable->findById($id)->getAnr(); + foreach ($instance->getChildren() as $childInstance) { + $childInstance->refreshInheritedImpact(); + + $this->instanceTable->save($childInstance, false); + + $this->updateRisks($childInstance); + + $this->updateChildrenImpactsAndRisks($childInstance); + } + } + + public function refreshInstanceImpactAndUpdateRisks(Entity\Instance $instance): void + { + $instance->updateImpactBasedOnConsequences(); + $this->updateRisks($instance); + $this->updateChildrenImpactsAndRisks($instance); + $instance->setUpdater($this->connectedUser->getEmail()); + + $this->instanceTable->save($instance, false); + } + + public function delete(Entity\Anr $anr, int $id): void + { + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($id, $anr); + + /* Only a root instance can be deleted. */ + if (!$instance->isLevelRoot()) { + throw new Exception('Only composition root instances can be deleted.', 412); + } + + $instance->removeAllInstanceRisks()->removeAllOperationalInstanceRisks(); - parent::delete($id); + $this->shiftPositionsForRemovingEntity($instance, $this->instanceTable); + + $this->instanceTable->remove($instance); // Reset related recommendations positions to 0. $unlinkedRecommendations = $this->recommendationTable->findUnlinkedWithNotEmptyPositionByAnr($anr); @@ -71,200 +260,177 @@ public function delete($id) } /** - * The code is extracted to be able to refactor the recommendations export, - * They are duplicated between instances and the code requires improvements itself. + * Creates instances for each child. */ - protected function generateExportArrayOfRecommendations( - InstanceSuperClass $instance, - bool $withEval, - bool $withRecommendations, - bool $withUnlinkedRecommendations, - array $riskIds, - array $riskOpIds - ): array { - $result = []; + private function createChildren(Entity\Instance $parentInstance): void + { + /** @var Entity\Anr $anr */ + $anr = $parentInstance->getAnr(); + foreach ($parentInstance->getObject()->getChildrenLinks() as $childObjectLink) { + $this->instantiateObjectToAnr($anr, [ + 'object' => $childObjectLink->getChild(), + 'parent' => $parentInstance, + 'position' => $childObjectLink->getPosition(), + 'setOnlyExactPosition' => true, + ]); + } + } - if ($withEval && $withRecommendations) { - $result['recSets'] = []; - - $recommendationsSets = $this->recommendationSetTable->findByAnr($instance->getAnr()); - foreach ($recommendationsSets as $recommendationSet) { - $result['recSets'][$recommendationSet->getUuid()] = [ - 'uuid' => $recommendationSet->getUuid(), - 'label1' => $recommendationSet->getLabel(1), - 'label2' => $recommendationSet->getLabel(2), - 'label3' => $recommendationSet->getLabel(3), - 'label4' => $recommendationSet->getLabel(4), - ]; - } + /** + * The level is used to determine if the related object has a composition and if not root (doesn't have it), + * then the instance can be removed or moved independently. + */ + private function updateInstanceLevels(bool $rootLevel, Entity\Instance $instance): void + { + if ($rootLevel) { + $instance->setLevel(CoreEntity\InstanceSuperClass::LEVEL_ROOT); + } elseif ($instance->getObject()->hasChildren()) { + $instance->setLevel(CoreEntity\InstanceSuperClass::LEVEL_INTER); + } else { + $instance->setLevel(CoreEntity\InstanceSuperClass::LEVEL_LEAF); } + } - $recoIds = []; - if ($withEval && $withRecommendations && !empty($riskIds)) { - $recosObj = [ - 'uuid' => 'uuid', - 'recommandationSet' => 'recommandationSet', - 'code' => 'code', - 'description' => 'description', - 'importance' => 'importance', - 'comment' => 'comment', - 'status' => 'status', - 'responsable' => 'responsable', - 'duedate' => 'duedate', - 'counterTreated' => 'counterTreated', - ]; - $result['recos'] = []; - if (!$withUnlinkedRecommendations) { - $result['recs'] = []; - } - /** @var RecommandationRisk[] $recoRisk */ - $recoRisk = $this->recommendationRiskTable->getEntityByFields( - ['anr' => $instance->getAnr()->getId(), 'instanceRisk' => $riskIds], - ['id' => 'ASC'] - ); - foreach ($recoRisk as $rr) { - $recommendation = $rr->getRecommandation(); - if ($recommendation !== null) { - $recommendationUuid = $recommendation->getUuid(); - $instanceRiskId = $rr->getInstanceRisk()->getId(); - $result['recos'][$instanceRiskId][$recommendationUuid] = $recommendation->getJsonArray($recosObj); - $result['recos'][$instanceRiskId][$recommendationUuid]['recommandationSet'] = - $recommendation->getRecommandationSet()->getUuid(); - $result['recos'][$instanceRiskId][$recommendationUuid]['commentAfter'] = $rr->getCommentAfter(); - if (!$withUnlinkedRecommendations && !isset($recoIds[$recommendationUuid])) { - $result['recs'][$recommendationUuid] = $recommendation->getJsonArray($recosObj); - $result['recs'][$recommendationUuid]['recommandationSet'] = - $recommendation->getRecommandationSet()->getUuid(); - } - $recoIds[$recommendationUuid] = $recommendationUuid; + private function updateOtherGlobalInstancesConsequences(Entity\Instance $instance): void + { + if ($instance->getObject()->isScopeGlobal()) { + /* Retrieve instances linked to the same global object to update impacts based on the passed instance. */ + foreach ($instance->getObject()->getInstances() as $otherGlobalInstance) { + if ($otherGlobalInstance->getId() !== $instance->getId()) { + /* Consequences of this instance supposed to be already updated before ::updateInstance, where + called ::updateConsequences, InstanceConsequenceService::patchConsequence and finally + InstanceConsequenceService::updateSiblingsConsequences. */ + $otherGlobalInstance->updateImpactBasedOnConsequences(); + $this->updateRisks($otherGlobalInstance); + $this->updateChildrenImpactsAndRisks($otherGlobalInstance); + $otherGlobalInstance->setUpdater($this->connectedUser->getEmail()); + + $this->instanceTable->save($otherGlobalInstance, false); } } } + } - if ($withEval && $withRecommendations && !empty($riskOpIds)) { - $recosObj = [ - 'uuid' => 'uuid', - 'recommandationSet' => 'recommandationSet', - 'code' => 'code', - 'description' => 'description', - 'importance' => 'importance', - 'comment' => 'comment', - 'status' => 'status', - 'responsable' => 'responsable', - 'duedate' => 'duedate', - 'counterTreated' => 'counterTreated', - ]; - $result['recosop'] = []; - if (!$withUnlinkedRecommendations) { - $result['recs'] = []; - } - $recoRisk = $this->recommendationRiskTable->getEntityByFields( - ['anr' => $instance->getAnr()->getId(), 'instanceRiskOp' => $riskOpIds], - ['id' => 'ASC'] - ); - foreach ($recoRisk as $rr) { - $recommendation = $rr->getRecommandation(); - if ($recommendation !== null) { - $instanceRiskOpId = $rr->getInstanceRiskOp()->getId(); - $recommendationUuid = $recommendation->getUuid(); - $result['recosop'][$instanceRiskOpId][$recommendationUuid] = - $recommendation->getJsonArray($recosObj); - $result['recosop'][$instanceRiskOpId][$recommendationUuid]['recommandationSet'] = - $recommendation->getRecommandationSet()->getUuid(); - $result['recosop'][$instanceRiskOpId][$recommendationUuid]['commentAfter'] = - $rr->getCommentAfter(); - if (!$withUnlinkedRecommendations && !isset($recoIds[$recommendationUuid])) { - $result['recs'][$recommendationUuid] = $recommendation->getJsonArray($recosObj); - $result['recs'][$recommendationUuid]['recommandationSet'] = - $recommendation->getRecommandationSet()->getUuid(); - } - $recoIds[$recommendationUuid] = $recommendationUuid; - } - } + private function updateConsequences(Entity\Anr $anr, array $consequencesData) + { + foreach ($consequencesData as $consequenceData) { + $this->anrInstanceConsequenceService->patchConsequence($anr, $consequenceData['id'], [ + 'confidentiality' => (int)$consequenceData['c_risk'], + 'integrity' => (int)$consequenceData['i_risk'], + 'availability' => (int)$consequenceData['d_risk'], + 'isHidden' => (int)$consequenceData['isHidden'], + ]); } + } - // Recommendation unlinked to recommandations-risks - if ($withUnlinkedRecommendations && $withEval && $withRecommendations) { - $recosObj = [ - 'uuid' => 'uuid', - 'recommandationSet' => 'recommandationSet', - 'code' => 'code', - 'description' => 'description', - 'importance' => 'importance', - 'comment' => 'comment', - 'status' => 'status', - 'responsable' => 'responsable', - 'duedate' => 'duedate', - 'counterTreated' => 'counterTreated', - ]; - $result['recs'] = []; - $recommendations = $this->recommendationTable->findByAnr($instance->getAnr()); - foreach ($recommendations as $recommendation) { - if (!isset($recoIds[$recommendation->getUuid()])) { - $result['recs'][$recommendation->getUuid()] = $recommendation->getJsonArray($recosObj); - $result['recs'][$recommendation->getUuid()]['recommandationSet'] = - $recommendation->getRecommandationSet()->getUuid(); - $recoIds[$recommendation->getUuid()] = $recommendation->getUuid(); - } + /** Recreates instance metadata based on one of others sibling global instances. */ + private function createInstanceMetadataFromGlobalSibling(Entity\Instance $instance): void + { + /** @var Entity\Instance $siblingInstance */ + $siblingInstance = $this->instanceTable->findOneByAnrAndObjectExcludeInstance( + $instance->getAnr(), + $instance->getObject(), + $instance + ); + if ($siblingInstance !== null) { + foreach ($siblingInstance->getInstanceMetadata() as $instanceMetadataOfSiblingInstance) { + $instanceMetadata = (new Entity\InstanceMetadata()) + ->setInstance($instance) + ->setAnrInstanceMetadataField($instanceMetadataOfSiblingInstance->getAnrInstanceMetadataField()) + ->setComment($instanceMetadataOfSiblingInstance->getComment()) + ->setCreator($this->connectedUser->getEmail()); + $this->instanceMetadataTable->save($instanceMetadata, false); } } - - return $result; } - protected function generateExportArrayOfInstancesMetadatas(InstanceSuperClass $instance): array + private function getChildrenTreeList(Entity\Instance $instance): array { $result = []; - $anr = $instance->getAnr(); - $translationTable = $this->get('translationTable'); - $language = $this->getAnrLanguageCode($anr); - $translations = $translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::INSTANCE_METADATA, Translation::ANR_METADATAS_ON_INSTANCES], - $language - ); - $instancesMetadatas = $instance->getInstanceMetadatas(); - foreach ($instancesMetadatas as $instanceMetadata) { - $translationComment = $translations[$instanceMetadata->getCommentTranslationKey()] ?? null; - $translationLabel = $translations[$instanceMetadata->getMetadata()->getLabelTranslationKey()] ?? null; - $result[$instanceMetadata->getMetadata()->getId()] = [ - 'label' => $translationLabel !== null ? $translationLabel->getValue() : '', - 'id' => $instanceMetadata->getId(), - 'comment' => $translationComment !== null ? $translationComment->getValue() : '', - ]; + foreach ($instance->getChildren() as $childInstance) { + $result[] = array_merge( + $this->getPreparedInstanceData($childInstance), + ['child' => $this->getChildrenTreeList($childInstance)] + ); } + return $result; } - protected function updateInstanceMetadataFromBrothers(InstanceSuperClass $instance): void + private function getPreparedInstanceData(Entity\Instance $instance): array { - /** @var InstanceTable $table */ - $instanceMetadataTable = $this->get('instanceMetadataTable'); - $table = $this->get('table'); + return array_merge([ + 'id' => $instance->getId(), + 'anr' => [ + 'id' => $instance->getAnr()->getId(), + ], + 'asset' => array_merge([ + 'uuid' => $instance->getAsset()->getUuid(), + 'type' => $instance->getAsset()->getType(), + ], $instance->getAsset()->getLabels()), + 'object' => array_merge([ + 'uuid' => $instance->getObject()->getUuid(), + 'scope' => $instance->getObject()->getScope(), + ], $instance->getObject()->getLabels(), $instance->getObject()->getNames()), + 'root' => $instance->isRoot() ? null : $instance->getRootInstance(), + 'parent' => $instance->hasParent() ? $instance->getParent() : null, + 'level' => $instance->getLevel(), + 'c' => $instance->getConfidentiality(), + 'i' => $instance->getIntegrity(), + 'd' => $instance->getAvailability(), + 'ch' => (int)$instance->isConfidentialityInherited(), + 'ih' => (int)$instance->isIntegrityInherited(), + 'dh' => (int)$instance->isAvailabilityInherited(), + 'position' => $instance->getPosition(), + 'scope' => $instance->getObject()->getScope(), + ], $instance->getLabels(), $instance->getNames()); + } + + private function getOtherInstances(Entity\Instance $instance): array + { + /** @var Entity\Anr $anr */ $anr = $instance->getAnr(); - $brothers = $table->findGlobalBrothersByAnrAndInstance($anr, $instance); - if (!empty($brothers)) { - $instanceBrother = current($brothers); - $instancesMetadatasFromBrother = $instanceBrother->getInstanceMetadatas(); - foreach ($instancesMetadatasFromBrother as $instanceMetadataFromBrother) { - $metadata = $instanceMetadataFromBrother->getMetadata(); - $instanceMetadata = $instanceMetadataTable - ->findByInstanceAndMetadata($instance, $metadata); - if ($instanceMetadata === null) { - $instanceMetadata = (new InstanceMetadata()) - ->setInstance($instance) - ->setMetadata($metadata) - ->setCommentTranslationKey($instanceMetadataFromBrother->getCommentTranslationKey()) - ->setCreator($this->getConnectedUser()->getEmail()); - $instanceMetadataTable->save($instanceMetadata, false); - } + $otherInstances = $this->instanceTable->findByAnrAndObject($anr, $instance->getObject()); + $names = [ + 'name1' => $anr->getLabel(), + 'name2' => $anr->getLabel(), + 'name3' => $anr->getLabel(), + 'name4' => $anr->getLabel(), + ]; + $otherInstancesData = []; + foreach ($otherInstances as $otherInstance) { + $names['id'] = $otherInstance->getId(); + foreach ($otherInstance->getHierarchyArray() as $instanceFromTheTree) { + $names['name1'] .= ' > ' . $instanceFromTheTree['name1']; + $names['name2'] .= ' > ' . $instanceFromTheTree['name2']; + $names['name3'] .= ' > ' . $instanceFromTheTree['name3']; + $names['name4'] .= ' > ' . $instanceFromTheTree['name4']; } - $instanceMetadataTable->flush(); + + $otherInstancesData[] = $names; } + + return $otherInstancesData; } - protected function getAnrLanguageCode(Anr $anr): string + private function updateRisks(Entity\Instance $instance): void { - return $this->get('configService')->getActiveLanguageCodes()[$anr->getLanguage()]; + foreach ($instance->getInstanceRisks() as $instanceRisk) { + $this->anrInstanceRiskService->recalculateRiskRatesAndUpdateRecommendationsPositions($instanceRisk); + $this->instanceRiskTable->save($instanceRisk, false); + } + } + + private function updateInstanceParent(Entity\Instance $instance, array $data): void + { + if (!empty($data['parent']) && $instance->getParent()?->getId() !== $data['parent']) { + /** @var Entity\Instance|null $parentInstance */ + $parentInstance = $this->instanceTable->findById((int)$data['parent'], false); + if ($parentInstance !== null) { + $instance->setParent($parentInstance)->setRoot($parentInstance->getRoot() ?? $parentInstance); + } + } elseif (empty($data['parent']) && $instance->hasParent()) { + $instance->setParent(null)->setRoot(null); + } } } diff --git a/src/Service/AnrInstanceServiceFactory.php b/src/Service/AnrInstanceServiceFactory.php deleted file mode 100755 index bef501b3..00000000 --- a/src/Service/AnrInstanceServiceFactory.php +++ /dev/null @@ -1,73 +0,0 @@ - Table\InstanceTable::class, - 'entity' => Instance::class, - 'anrTable' => Table\AnrTable::class, - 'assetTable' => Table\AssetTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'amvTable' => Table\AmvTable::class, - 'objectTable' => Table\MonarcObjectTable::class, - 'scaleTable' => Table\ScaleTable::class, - 'scaleImpactTypeTable' => Table\ScaleImpactTypeTable::class, - 'instanceConsequenceTable' => Table\InstanceConsequenceTable::class, - 'instanceRiskTable' => Table\InstanceRiskTable::class, - 'instanceRiskOpTable' => Table\InstanceRiskOpTable::class, - 'instanceConsequenceEntity' => InstanceConsequence::class, - 'recommendationRiskTable' => Table\RecommandationRiskTable::class, - 'recommendationTable' => Table\RecommandationTable::class, - 'recommendationSetTable' => Table\RecommandationSetTable::class, - 'themeTable' => Table\ThemeTable::class, - 'translationTable' => Table\TranslationTable::class, - 'instanceMetadataTable' => Table\InstanceMetadataTable::class, - - // Services - 'instanceConsequenceService' => AnrInstanceConsequenceService::class, - 'instanceRiskService' => AnrInstanceRiskService::class, - 'instanceRiskOpService' => AnrInstanceRiskOpService::class, - 'objectObjectService' => ObjectObjectService::class, - 'translateService' => TranslateService::class, - 'configService' => ConfigService::class, - 'operationalRiskScalesExportService' => OperationalRiskScalesExportService::class, - 'anrMetadatasOnInstancesExportService' => AnrMetadatasOnInstancesExportService::class, - - // Export Services - 'objectExportService' => ObjectExportService::class, - 'amvService' => AmvService::class, - ]; - - // TODO: A temporary solution to inject SharedEventManager. All the factories classes will be removed. - public function __invoke(ContainerInterface $container, $requestedName, array $options = null) - { - $objectObjectService = parent::__invoke($container, $requestedName, $options); - - $objectObjectService->setSharedManager($container->get('EventManager')->getSharedManager()); - - return $objectObjectService; - } -} diff --git a/src/Service/AnrInterviewServiceFactory.php b/src/Service/AnrInterviewServiceFactory.php index 576032fc..c23a4519 100755 --- a/src/Service/AnrInterviewServiceFactory.php +++ b/src/Service/AnrInterviewServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Factory class attached to AnrInterviewService @@ -17,8 +19,8 @@ class AnrInterviewServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\InterviewTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Interview', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', + 'entity' => 'Monarc\FrontOffice\Entity\Interview', + 'anrTable' => AnrTable::class, + 'userAnrTable' => UserAnrTable::class, ]; } diff --git a/src/Service/AnrLibraryService.php b/src/Service/AnrLibraryService.php deleted file mode 100644 index 31ef3e37..00000000 --- a/src/Service/AnrLibraryService.php +++ /dev/null @@ -1,11 +0,0 @@ - MonarcObjectTable::class, - 'entity' => MonarcObject::class, - 'objectObjectTable' => ObjectObjectTable::class, - 'objectService' => AnrObjectService::class, - 'userAnrTable' => UserAnrTable::class, - ]; -} diff --git a/src/Service/AnrMeasureLinkService.php b/src/Service/AnrMeasureLinkService.php new file mode 100644 index 00000000..f96775c6 --- /dev/null +++ b/src/Service/AnrMeasureLinkService.php @@ -0,0 +1,83 @@ +measureTable->findByAnr($anr) as $masterMeasure) { + foreach ($masterMeasure->getLinkedMeasures() as $linkedMeasure) { + $result[] = [ + 'masterMeasure' => array_merge([ + 'uuid' => $masterMeasure->getUuid(), + 'code' => $masterMeasure->getCode(), + ], $masterMeasure->getLabels()), + 'linkedMeasure' => array_merge([ + 'uuid' => $linkedMeasure->getUuid(), + 'code' => $linkedMeasure->getCode(), + ], $linkedMeasure->getLabels()), + ]; + } + } + + return $result; + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\Measure + { + if ($data['masterMeasureUuid'] === $data['linkedMeasureUuid']) { + throw new Exception('It is not possible to link a control to itself', 412); + } + + /** @var Entity\Measure $masterMeasure */ + $masterMeasure = $this->measureTable->findByUuidAndAnr($data['masterMeasureUuid'], $anr); + /** @var Entity\Measure $linkedMeasure */ + $linkedMeasure = $this->measureTable->findByUuidAndAnr($data['linkedMeasureUuid'], $anr); + + $masterMeasure->addLinkedMeasure($linkedMeasure); + $this->measureTable->save($linkedMeasure, $saveInDb); + + return $masterMeasure; + } + + /** + * @return string[] + */ + public function createList(Entity\Anr $anr, array $data): array + { + $createdIds = []; + foreach ($data as $rowData) { + $createdIds[] = $this->create($anr, $rowData, false)->getUuid(); + } + $this->measureTable->flush(); + + return $createdIds; + } + + public function delete(Entity\Anr $anr, string $masterMeasureUuid, string $linkedMeasureUuid): void + { + /** @var Entity\Measure $masterMeasure */ + $masterMeasure = $this->measureTable->findByUuidAndAnr($masterMeasureUuid, $anr); + /** @var Entity\Measure $linkedMeasure */ + $linkedMeasure = $this->measureTable->findByUuidAndAnr($linkedMeasureUuid, $anr); + $masterMeasure->removeLinkedMeasure($linkedMeasure); + + $this->measureTable->save($masterMeasure); + } +} diff --git a/src/Service/AnrMeasureMeasureService.php b/src/Service/AnrMeasureMeasureService.php deleted file mode 100644 index 13036351..00000000 --- a/src/Service/AnrMeasureMeasureService.php +++ /dev/null @@ -1,75 +0,0 @@ -get('anrTable'); - $measureMeasureTable = $this->get('table'); - $measuresMeasures = $measureMeasureTable->getEntityByFields([ - 'anr' => $data['anr'], - 'child' => $data['child']['uuid'], - 'father' => $data['father']['uuid'] - ]); - - if (!empty($measuresMeasures)) { // the linkk already exist - throw new Exception('This component already exist for this object', 412); - } - - $anr = $anrTable->getEntity($data['anr']); - - /** @var MeasureMeasure $measureMeasure */ - $measureMeasureClass = $this->get('entity'); - $measureMeasure = new $measureMeasureClass(); - $measureMeasure->setAnr($anr); - $measureMeasure->setFather($data['father']['uuid']); - $measureMeasure->setChild($data['child']['uuid']); - $measureMeasureTable->save($measureMeasure, false); - $measureMeasureReversed = clone $measureMeasure; - $measureMeasureReversed->setFather($data['child']['uuid']); - $measureMeasureReversed->setChild($data['father']['uuid']); - $measureMeasureTable->save($measureMeasureReversed); - - return null; - } - - public function delete($id) - { - $measureTable = $this->get('measureTable'); - $father = $measureTable->getEntity(['uuid' => $id['father'], 'anr' => $id['anr']]); - $child = $measureTable->getEntity(['uuid' => $id['child'], 'anr' => $id['anr']]); - $father->deleteLinkedMeasure($child); - - $measureTable->save($father); - } -} diff --git a/src/Service/AnrMeasureMeasureServiceFactory.php b/src/Service/AnrMeasureMeasureServiceFactory.php deleted file mode 100644 index c46749f4..00000000 --- a/src/Service/AnrMeasureMeasureServiceFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\MeasureMeasure', - 'table' => 'Monarc\FrontOffice\Model\Table\MeasureMeasureTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'measureTable' => 'Monarc\FrontOffice\Model\Table\MeasureTable', - // 'category' => 'Monarc\FrontOffice\Model\Entity\Category' - ]; -} diff --git a/src/Service/AnrMeasureService.php b/src/Service/AnrMeasureService.php index 71848271..79f3efe7 100755 --- a/src/Service/AnrMeasureService.php +++ b/src/Service/AnrMeasureService.php @@ -1,58 +1,185 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $params): array + { + $result = []; + + $includeLinks = $params->hasFilterFor('includeLinks') && $params->getFilterFor('includeLinks')['value']; + /** @var Entity\Measure $measure */ + foreach ($this->measureTable->findByParams($params) as $measure) { + $result[] = $this->prepareMeasureDataResult($measure, $includeLinks); + } + + return $result; + } + + public function getCount(FormattedInputParams $params): int + { + return $this->measureTable->countByParams($params); + } + + public function getMeasureData(Entity\Anr $anr, string $uuid): array + { + /** @var Entity\Measure $measure */ + $measure = $this->measureTable->findByUuidAndAnr($uuid, $anr); + + return $this->prepareMeasureDataResult($measure); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\Measure + { + /** @var Entity\Referential $referential */ + $referential = $this->referentialTable->findByUuidAndAnr($data['referentialUuid'], $anr); + /** @var Entity\SoaCategory $soaCategory */ + $soaCategory = $this->soaCategoryTable->findByIdAndAnr($data['categoryId'], $anr); + + $measure = $this->createMeasureObject($anr, $referential, $soaCategory, $data, $saveInDb); + + $this->soaService->createSoaObject($anr, $measure); + + return $measure; + } + + public function createMeasureObject( + Entity\Anr $anr, + Entity\Referential $referential, + ?Entity\SoaCategory $soaCategory, + array $data, + bool $saveInDb = true + ): Entity\Measure { + /** @var Entity\Measure $measure */ + $measure = (new Entity\Measure()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels($data) + ->setReferential($referential) + ->setCategory($soaCategory) + ->setCreator($this->connectedUser->getEmail()); + if (!empty($data['uuid'])) { + $measure->setUuid($data['uuid']); + } + + $this->measureTable->save($measure, $saveInDb); + + return $measure; + } + + public function createList(Entity\Anr $anr, array $data): array + { + $createdUuids = []; + foreach ($data as $row) { + $createdUuids[] = $this->create($anr, $row, false)->getUuid(); + } + $this->measureTable->flush(); + + return $createdUuids; + } + + public function update(Entity\Anr $anr, string $uuid, array $data): Entity\Measure + { + /** @var Entity\Measure $measure */ + $measure = $this->measureTable->findByUuidAndAnr($uuid, $anr); + $measure->setLabels($data) + ->setCode($data['code']) + ->setUpdater($this->connectedUser->getEmail()); + if ($measure->getCategory() === null || $measure->getCategory()->getId() !== $data['categoryId']) { + $previousLinkedCategory = $measure->getCategory(); + /** @var Entity\SoaCategory $soaCategory */ + $soaCategory = $this->soaCategoryTable->findByIdAndAnr($data['categoryId'], $anr); + $measure->setCategory($soaCategory); + if ($previousLinkedCategory !== null && $previousLinkedCategory->getMeasures()->isEmpty()) { + $this->soaCategoryTable->remove($previousLinkedCategory, false); + } + } + + $this->measureTable->save($measure); + + return $measure; + } + + public function delete(Entity\Anr $anr, string $uuid): void + { + /** @var Entity\Measure $measure */ + $measure = $this->measureTable->findByUuidAndAnr($uuid, $anr); + + $this->processMeasureRemoval($measure); + } + + public function deleteList(Entity\Anr $anr, array $data) + { + /** @var Entity\Measure[] $measures */ + $measures = $this->measureTable->findByUuidsAndAnr($data, $anr); + + foreach ($measures as $measure) { + $this->processMeasureRemoval($measure, false); + } + $this->measureTable->flush(); + } + + private function processMeasureRemoval(Entity\Measure $measure, bool $saveInDb = true): void + { + $previousLinkedCategory = $measure->getCategory(); + $measure->setCategory(null); + if ($previousLinkedCategory !== null && $previousLinkedCategory->getMeasures()->isEmpty()) { + $this->soaCategoryTable->remove($previousLinkedCategory, false); } - $table = $this->get('table'); - $SoaClass = $this->get('soaEntity'); - $SoaTable = $this->get('soaTable'); - $anrTable = $this->get('anrTable'); - $measure = $table->getEntity(['uuid' =>$uuid,'anr'=>$data['anr']]); - $anr = $anrTable->getEntity($data['anr']); - $SoaEntity = new $SoaClass(); - $SoaEntity->setMeasure($measure); - $SoaEntity->setAnr($anr); - $SoaTable->save($SoaEntity, $last); + + $this->measureTable->remove($measure, $saveInDb); + } + + private function prepareMeasureDataResult(Entity\Measure $measure, bool $includeLinks = false): array + { + $linkedMeasures = []; + if ($includeLinks) { + /** @var Entity\Measure $linkedMeasure */ + foreach ($measure->getLinkedMeasures() as $linkedMeasure) { + $linkedMeasures[] = array_merge([ + 'id' => $linkedMeasure->getId(), + 'uuid' => $linkedMeasure->getUuid(), + 'code' => $linkedMeasure->getCode(), + ], $linkedMeasure->getLabels()); + } + } + + return array_merge([ + 'id' => $measure->getId(), + 'uuid' => $measure->getUuid(), + 'referential' => array_merge([ + 'uuid' => $measure->getReferential()->getUuid(), + ], $measure->getReferential()->getLabels()), + 'code' => $measure->getCode(), + 'category' => $measure->getCategory() === null + ? [] + : array_merge(['id' => $measure->getCategory()->getId()], $measure->getCategory()->getLabels()), + 'status' => $measure->getStatus(), + 'linkedMeasures' => $linkedMeasures, + ], $measure->getLabels()); } } diff --git a/src/Service/AnrMeasureServiceFactory.php b/src/Service/AnrMeasureServiceFactory.php deleted file mode 100755 index f6947a0d..00000000 --- a/src/Service/AnrMeasureServiceFactory.php +++ /dev/null @@ -1,27 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Measure', - 'table' => 'Monarc\FrontOffice\Model\Table\MeasureTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'soaEntity' => 'Monarc\FrontOffice\Model\Entity\Soa', - 'soaTable' => 'Monarc\FrontOffice\Model\Table\SoaTable', - 'soaCategoryTable' => 'Monarc\FrontOffice\Model\Table\SoaCategoryTable', - ]; -} diff --git a/src/Service/AnrMetadatasOnInstancesService.php b/src/Service/AnrMetadatasOnInstancesService.php deleted file mode 100644 index ad46079b..00000000 --- a/src/Service/AnrMetadatasOnInstancesService.php +++ /dev/null @@ -1,117 +0,0 @@ -anrMetadatasOnInstancesTable->findById($id); - if ($metadataToDelete === null) { - throw new EntityNotFoundException(sprintf('Metadata with ID %d is not found', $id)); - } - - if ($metadataToDelete->isDeletable()) { - $this->anrMetadatasOnInstancesTable->remove($metadataToDelete); - - $translationsKeys[] = $metadataToDelete->getLabelTranslationKey(); - - if (!empty($translationsKeys)) { - $this->translationTable->deleteListByKeys($translationsKeys); - } - } - } - - /** - * @param int $anrId - * @param array $data - * - * @return array - * @throws EntityNotFoundException - * @throws ORMException - * @throws OptimisticLockException - */ - public function createAnrMetadatasOnInstances(int $anrId, array $data): array - { - $anr = $this->anrTable->findById($anrId); - $returnValue = []; - $data = (isset($data['metadatas']) ? $data['metadatas'] : $data); - foreach ($data as $inputMetadata) { - $metadata = (new AnrMetadatasOnInstances()) - ->setAnr($anr) - ->setLabelTranslationKey((string)Uuid::uuid4()) - ->setCreator($this->connectedUser->getEmail()) - ->setIsDeletable(true); - - $this->anrMetadatasOnInstancesTable->save($metadata); - $returnValue[] = $metadata->getId(); - - foreach ($inputMetadata as $lang => $labelText) { - $translation = $this->createTranslationObject( - $anr, - Translation::ANR_METADATAS_ON_INSTANCES, - $metadata->getLabelTranslationKey(), - $lang, - (string)$labelText - ); - $this->translationTable->save($translation); - } - } - - return $returnValue; - } - - protected function createTranslationObject( - AnrSuperClass $anr, - string $type, - string $key, - string $lang, - string $value - ): TranslationSuperClass { - return (new Translation()) - ->setAnr($anr) - ->setType($type) - ->setKey($key) - ->setLang($lang) - ->setValue($value) - ->setCreator($this->connectedUser->getEmail()); - } -} diff --git a/src/Service/AnrModelService.php b/src/Service/AnrModelService.php new file mode 100644 index 00000000..2fc3209b --- /dev/null +++ b/src/Service/AnrModelService.php @@ -0,0 +1,163 @@ +clientTable->findFirstClient()->getClientModels() as $clientModel) { + $modelIds[] = $clientModel->getModelId(); + } + foreach ($this->modelTable->fundGenericsAndSpecificsByIds($modelIds) as $model) { + $result[] = array_merge(['id' => $model->getId()], $model->getLabels()); + } + + return $result; + } + + /** + * Returns an array that specifies in which languages the model can be instantiated. + * + * @return array The array of languages that are available for the model. + * e.g. [1 => true, 2 => true, 3 => false, 4 => true] + */ + public function getAvailableLanguages(int $modelId): array + { + $languageIndexes = [1, 2, 3, 4]; + $result = []; + foreach ($languageIndexes as $languageIndex) { + $result[$languageIndex] = true; + } + + /** @var CoreEntity\Model $model */ + $model = $this->modelTable->findById($modelId); + $this->validateEntityLanguages($model, $result); + + /* Validates measures, rolf tags, rolf risks, questions and questions choices. */ + /** @var CoreEntity\Measure $measure */ + foreach ($this->coreMeasureTable->findAll() as $measure) { + $this->validateEntityLanguages($measure, $result); + } + /** @var CoreEntity\RolfRisk $rolfRisk */ + foreach ($this->coreRolfRiskTable->findAll() as $rolfRisk) { + $this->validateEntityLanguages($rolfRisk, $result); + } + /** @var CoreEntity\RolfTag $rolfTag */ + foreach ($this->coreRolfTagTable->findAll() as $rolfTag) { + $this->validateEntityLanguages($rolfTag, $result); + } + /** @var CoreEntity\Question $question */ + foreach ($this->coreQuestionTable->fetchAllObject() as $question) { + $this->validateEntityLanguages($question, $result); + } + /** @var CoreEntity\QuestionChoice $questionChoice */ + foreach ($this->coreQuestionChoiceTable->fetchAllObject() as $questionChoice) { + $this->validateEntityLanguages($questionChoice, $result); + } + + /** @var CoreEntity\ScaleImpactType $scaleImpactType */ + foreach ($this->coreScaleImpactTypeTable->findByAnr($model->getAnr()) as $scaleImpactType) { + $this->validateEntityLanguages($scaleImpactType, $result); + } + + /* Generic assets validation. */ + foreach ($this->coreAssetTable->findByMode(CoreEntity\AssetSuperClass::MODE_GENERIC) as $asset) { + $this->validateEntityLanguages($asset, $result); + } + /* Generic threats and themes validation. */ + foreach ($this->coreThreatTable->findByMode(CoreEntity\ThreatSuperClass::MODE_GENERIC) as $threat) { + foreach ($languageIndexes as $languageIndex) { + if (empty($threat->getLabel($languageIndex)) + || ($threat->getTheme() !== null + && empty($threat->getTheme()->getLabel($languageIndex)) + ) + ) { + $result[$languageIndex] = false; + } + } + } + /* Generic vulnerabilities validation. */ + $vulnerabilities = $this->coreVulnerabilityTable->findByMode(CoreEntity\VulnerabilitySuperClass::MODE_GENERIC); + foreach ($vulnerabilities as $vulnerability) { + $this->validateEntityLanguages($vulnerability, $result); + } + /* If the models is specific, the linked objects have to be validated as well. */ + if (!$model->isGeneric()) { + foreach ($model->getAssets() as $specificAsset) { + $this->validateEntityLanguages($specificAsset, $result); + } + foreach ($model->getThreats() as $specificThreat) { + foreach ($languageIndexes as $languageIndex) { + if (empty($specificThreat->getLabel($languageIndex)) + || ($specificThreat->getTheme() !== null + && empty($specificThreat->getTheme()->getLabel($languageIndex)) + ) + ) { + $result[$languageIndex] = false; + } + } + } + foreach ($model->getVulnerabilities() as $specificVulnerability) { + $this->validateEntityLanguages($specificVulnerability, $result); + } + } + + /* Validates monarc objects. */ + /** @var CoreEntity\MonarcObject $monarcObject */ + foreach ($model->getAnr() ? $model->getAnr()->getObjects() : [] as $monarcObject) { + foreach ($languageIndexes as $languageIndex) { + if (empty($monarcObject->getLabel($languageIndex)) + || empty($monarcObject->getName($languageIndex)) + || ($monarcObject->getCategory() !== null + && empty($monarcObject->getCategory()->getLabel($languageIndex)) + ) + ) { + $result[$languageIndex] = false; + } + } + } + + return $result; + } + + /** + * @param object $entity + * @param array $resultLanguages e.g. [1 => true, 2 => false, 3 => true, 4 => false] + */ + private function validateEntityLanguages(object $entity, array &$resultLanguages): void + { + foreach (array_keys($resultLanguages) as $languageIndex) { + if (method_exists($entity, 'getLabel') && empty($entity->getLabel($languageIndex))) { + $resultLanguages[$languageIndex] = false; + } + } + } +} diff --git a/src/Service/AnrObjectCategoryService.php b/src/Service/AnrObjectCategoryService.php index 69b6919e..cd665ec3 100644 --- a/src/Service/AnrObjectCategoryService.php +++ b/src/Service/AnrObjectCategoryService.php @@ -1,42 +1,220 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getObjectCategoryData(Entity\Anr $anr, int $id): array { - /** @var AnrObjectCategoryTable $anrObjectCategoryTable */ - $anrObjectCategoryTable = $this->get('anrObjectCategoryTable'); + /** @var Entity\ObjectCategory $objectCategory */ + $objectCategory = $this->objectCategoryTable->findByIdAndAnr($id, $anr); - $anrObjectCategory = $anrObjectCategoryTable->findOneByAnrAndObjectCategory( - $objectCategory->getAnr(), - $objectCategory - ); - if ($anrObjectCategory !== null) { - $anrObjectCategoryTable->delete($anrObjectCategory->getId()); + $objectCategoryData = [ + 'id' => $objectCategory->getId(), + 'root' => $objectCategory->getRoot() !== null + ? ['id' => $objectCategory->getRoot()->getId()] + : null, + 'parent' => $objectCategory->hasParent() + ? [ + 'id' => $objectCategory->getParent()->getId(), + 'label' . $anr->getLanguage() => $objectCategory->getParent()->getLabel($anr->getLanguage()), + ] + : null, + 'label' . $anr->getLanguage() => $objectCategory->getLabel($anr->getLanguage()), + 'position' => $objectCategory->getPosition(), + 'previous' => null, + 'implicitPosition' => 1, + ]; + + if ($objectCategory->getPosition() > 1) { + $maxPosition = $this->objectCategoryTable + ->findMaxPosition($objectCategory->getImplicitPositionRelationsValues()); + if ($objectCategory->getPosition() >= $maxPosition) { + $objectCategoryData['implicitPosition'] = PositionUpdatableServiceInterface::IMPLICIT_POSITION_END; + } else { + $objectCategoryData['implicitPosition'] = PositionUpdatableServiceInterface::IMPLICIT_POSITION_AFTER; + $previousObjectCategory = $this->objectCategoryTable->findPreviousCategory($objectCategory); + if ($previousObjectCategory !== null) { + $objectCategoryData['previous'] = $previousObjectCategory->getId(); + } + } } + + return $objectCategoryData; } - protected function linkCategoryToAnr(ObjectCategorySuperClass $objectCategory): void + public function getList(FormattedInputParams $formattedInputParams) { - /** @var AnrObjectCategoryTable $anrObjectCategoryTable */ - $anrObjectCategoryTable = $this->get('anrObjectCategoryTable'); - if ($anrObjectCategoryTable - ->findOneByAnrAndObjectCategory($objectCategory->getAnr(), $objectCategory) === null + $includeChildren = empty($formattedInputParams->getFilterFor('parentId')['value']) + || empty($formattedInputParams->getFilterFor('lock')['value']); + + /* Fetch only root categories and populate their children in case if no filter by parentId or categoryId. */ + if ($includeChildren && empty($formattedInputParams->getFilterFor('catid')['value'])) { + $formattedInputParams->setFilterValueFor('parent', null); + } + + $categoriesData = []; + /** @var Entity\ObjectCategory $objectCategory */ + foreach ($this->objectCategoryTable->findByParams($formattedInputParams) as $objectCategory) { + $categoriesData[] = $this->getPreparedObjectCategoryData($objectCategory, $includeChildren); + } + + return $categoriesData; + } + + public function getCount(FormattedInputParams $params): int + { + return $this->objectCategoryTable->countByParams($params); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\ObjectCategory + { + $objectCategory = (new Entity\ObjectCategory()) + ->setAnr($anr) + ->setLabels($data) + ->setCreator($this->connectedUser->getEmail()); + + if (!empty($data['parent'])) { + /** @var Entity\ObjectCategory $parent */ + $parent = $data['parent'] instanceof Entity\ObjectCategory + ? $data['parent'] + : $this->objectCategoryTable->findByIdAndAnr((int)$data['parent'], $anr); + $objectCategory->setParent($parent); + $objectCategory->setRoot($parent->getRootCategory()); + } + + $this->updatePositions($objectCategory, $this->objectCategoryTable, $data); + + $this->objectCategoryTable->save($objectCategory, $saveInDb); + + return $objectCategory; + } + + public function update(Entity\Anr $anr, int $id, array $data): Entity\ObjectCategory + { + /** @var Entity\ObjectCategory $objectCategory */ + $objectCategory = $this->objectCategoryTable->findByIdAndAnr($id, $anr); + + $objectCategory->setLabels($data)->setUpdater($this->connectedUser->getEmail()); + + /* + * Perform operations to update the category's parent and root if necessary. + * 1 condition. The case when the category's parent is changed. Before the category could be root or a child. + * 2 condition. The case when the category becomes root (parent removed), and before it had a parent. + */ + if (!empty($data['parent']) + && (!$objectCategory->hasParent() || (int)$data['parent'] !== $objectCategory->getParent()?->getId()) ) { - $anrObjectCategory = new AnrObjectCategory(); - $anrObjectCategory->setAnr($objectCategory->getAnr())->setCategory($objectCategory); + /** @var Entity\ObjectCategory $parentCategory */ + $parentCategory = $this->objectCategoryTable->findByIdAndAnr((int)$data['parent'], $anr); + + /** @var Entity\ObjectCategory $previousRootCategory */ + $isRootCategoryBeforeUpdated = $objectCategory->isCategoryRoot(); + $hasRootCategoryChanged = $objectCategory->hasParent() + && $parentCategory->getRootCategory()->getId() !== $objectCategory->getRootCategory()->getId(); + + $objectCategory->setParent($parentCategory)->setRoot($parentCategory->getRootCategory()); + + if ($isRootCategoryBeforeUpdated || $hasRootCategoryChanged) { + /* Update the category children with the new root. */ + $this->updateRootOfChildrenTree($objectCategory); + } + } elseif (empty($data['parent']) && $objectCategory->hasParent()) { + $objectCategory->setParent(null)->setRoot(null); + + /* Update the category children with the new root. */ + $this->updateRootOfChildrenTree($objectCategory); + } + + $this->updatePositions( + $objectCategory, + $this->objectCategoryTable, + array_merge($data, ['forcePositionUpdate' => true]) + ); + + $this->objectCategoryTable->save($objectCategory); + + return $objectCategory; + } + + public function delete(Entity\Anr $anr, int $id): void + { + /** @var Entity\ObjectCategory $objectCategory */ + $objectCategory = $this->objectCategoryTable->findByIdAndAnr($id, $anr); + + /* Remove all the relations with ANRs and adjust the overall positions. */ + $this->shiftPositionsForRemovingEntity($objectCategory, $this->objectCategoryTable); - $anrObjectCategory->setDbAdapter($anrObjectCategoryTable->getDb()); - $anrObjectCategory->exchangeArray(['implicitPosition' => 2]); + /* Set the removing category's parent for all its children */ + foreach ($objectCategory->getChildren() as $childCategory) { + $childCategory->setParent($objectCategory->getParent())->setUpdater($this->connectedUser->getEmail()); + + /* If the removing category is root, then all its direct children become root. */ + if ($objectCategory->isCategoryRoot()) { + $childCategory->setRoot(null); + } + + $this->updatePositions($childCategory, $this->objectCategoryTable, ['forcePositionUpdate' => true]); + + $this->objectCategoryTable->save($childCategory); + } + + $this->objectCategoryTable->remove($objectCategory); + } + + private function getPreparedObjectCategoryData( + Entity\ObjectCategory $objectCategory, + bool $includeChildren = true + ): array { + $result = [ + 'id' => $objectCategory->getId(), + 'label1' => $objectCategory->getLabel(1), + 'label2' => $objectCategory->getLabel(2), + 'label3' => $objectCategory->getLabel(3), + 'label4' => $objectCategory->getLabel(4), + 'position' => $objectCategory->getPosition(), + ]; + + if ($includeChildren) { + foreach ($objectCategory->getChildren() as $childCategory) { + $result['child'][] = $this->getPreparedObjectCategoryData($childCategory); + } + } + + return $result; + } + + private function updateRootOfChildrenTree(Entity\ObjectCategory $objectCategory): void + { + foreach ($objectCategory->getChildren() as $childCategory) { + $childCategory->setRoot($objectCategory->getRootCategory()); + $this->objectCategoryTable->save($childCategory, false); - $anrObjectCategoryTable->save($anrObjectCategory); + $this->updateRootOfChildrenTree($childCategory); } } } diff --git a/src/Service/AnrObjectCategoryServiceFactory.php b/src/Service/AnrObjectCategoryServiceFactory.php deleted file mode 100755 index bef8abe6..00000000 --- a/src/Service/AnrObjectCategoryServiceFactory.php +++ /dev/null @@ -1,30 +0,0 @@ - Table\ObjectCategoryTable::class, - 'entity' => ObjectCategory::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'anrObjectCategoryTable' => Table\AnrObjectCategoryTable::class, - 'monarcObjectTable' => Table\MonarcObjectTable::class, - 'anrTable' => Table\AnrTable::class, - ]; -} diff --git a/src/Service/AnrObjectObjectService.php b/src/Service/AnrObjectObjectService.php new file mode 100644 index 00000000..6892144d --- /dev/null +++ b/src/Service/AnrObjectObjectService.php @@ -0,0 +1,201 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\ObjectObject + { + if ($data['parent'] === $data['child']) { + throw new Exception('It\'s not allowed to compose the same child object as parent.', 412); + } + + /** @var Entity\MonarcObject $parentObject */ + $parentObject = $this->monarcObjectTable->findByUuidAndAnr($data['parent'], $anr); + /** @var Entity\MonarcObject $childObject */ + $childObject = $this->monarcObjectTable->findByUuidAndAnr($data['child'], $anr); + if ($parentObject->hasChild($childObject)) { + throw new Exception('The object is already presented in the composition.', 412); + } + + if ($parentObject->isModeGeneric() && $childObject->isModeSpecific()) { + throw new Exception('It\'s not allowed to add a specific object to a generic parent', 412); + } + + /* Validate if one of the parents is the current child or its children. */ + $this->validateIfObjectOrItsChildrenLinkedToOneOfParents($childObject, $parentObject); + + $objectObject = $this->createObjectLink($parentObject, $childObject, $data, $saveInDb); + + /* Create instances of child object if necessary. */ + if ($parentObject->hasInstances()) { + $this->createInstances($parentObject, $childObject, $data); + } + + return $objectObject; + } + + public function createObjectLink( + Entity\MonarcObject $parentObject, + Entity\MonarcObject $childObject, + array $positionData, + bool $saveInDb + ): Entity\ObjectObject { + $objectObject = (new Entity\ObjectObject()) + ->setAnr($parentObject->getAnr()) + ->setParent($parentObject) + ->setChild($childObject) + ->setCreator($this->connectedUser->getEmail()); + + $this->updatePositions($objectObject, $this->objectObjectTable, $positionData); + + $this->objectObjectTable->save($objectObject, $saveInDb); + + return $objectObject; + } + + public function shiftPositionInComposition(Entity\Anr $anr, int $id, array $data): void + { + /** @var Entity\ObjectObject $objectObject */ + $objectObject = $this->objectObjectTable->findByIdAndAnr($id, $anr); + + /* Validate if the position is within the bounds of shift. */ + if (($data['move'] === static::MOVE_COMPOSITION_POSITION_UP && $objectObject->getPosition() <= 1) + || ( + $data['move'] === static::MOVE_COMPOSITION_POSITION_DOWN + && $objectObject->getPosition() >= $this->objectObjectTable->findMaxPosition( + $objectObject->getImplicitPositionRelationsValues() + ) + ) + ) { + return; + } + + $positionToBeSet = $data['move'] === static::MOVE_COMPOSITION_POSITION_UP + ? $objectObject->getPosition() - 1 + : $objectObject->getPosition() + 1; + /** @var Entity\MonarcObject $parentObject */ + $parentObject = $objectObject->getParent(); + $previousObjectCompositionLink = $this->objectObjectTable->findByParentObjectAndPosition( + $parentObject, + $positionToBeSet + ); + /* Some positions are not aligned in the DB, that's why we may have empty result. */ + if ($previousObjectCompositionLink !== null) { + $this->objectObjectTable->save( + $previousObjectCompositionLink->setPosition($objectObject->getPosition())->setUpdater( + $this->connectedUser->getEmail() + ), + false + ); + } + $this->objectObjectTable->save( + $objectObject->setPosition($positionToBeSet)->setUpdater($this->connectedUser->getEmail()) + ); + } + + public function delete(Entity\Anr $anr, int $id): void + { + /** @var Entity\ObjectObject $objectObject */ + $objectObject = $this->objectObjectTable->findByIdAndAnr($id, $anr); + + /* Unlink the related instances of the compositions. */ + foreach ($objectObject->getChild()->getInstances() as $childObjectInstance) { + foreach ($objectObject->getParent()->getInstances() as $parentObjectInstance) { + if ($childObjectInstance->hasParent() + && $childObjectInstance->getParent()?->getId() === $parentObjectInstance->getId() + ) { + $childObjectInstance->setParent(null); + $childObjectInstance->setRoot(null); + $this->instanceTable->remove($childObjectInstance, false); + } + } + } + + /* Shift positions to fill in the gap of the object being removed. */ + $this->shiftPositionsForRemovingEntity($objectObject, $this->objectObjectTable); + + $this->objectObjectTable->remove($objectObject); + } + + /** + * New instance is created when the composition parent object is presented in the analysis. + */ + private function createInstances( + Entity\MonarcObject $parentObject, + Entity\MonarcObject $childObject, + array $data + ): void { + $previousObjectCompositionLink = null; + if ($data['implicitPosition'] === PositionUpdatableServiceInterface::IMPLICIT_POSITION_AFTER) { + /** @var Entity\ObjectObject $previousObjectCompositionLink */ + $previousObjectCompositionLink = $this->objectObjectTable->findByIdAndAnr( + $data['previous'], + $parentObject->getAnr() + ); + } + foreach ($parentObject->getInstances() as $parentObjectInstance) { + $instanceData = [ + 'object' => $childObject, + 'parent' => $parentObjectInstance, + 'implicitPosition' => $data['implicitPosition'], + ]; + if ($previousObjectCompositionLink !== null) { + foreach ($previousObjectCompositionLink->getChild()->getInstances() as $previousObjectInstance) { + if ($previousObjectInstance->hasParent() + && $previousObjectInstance->getParent()?->getId() === $parentObjectInstance->getId() + ) { + $instanceData['previous'] = $previousObjectInstance->getId(); + } + } + } + + /** @var Entity\Anr $anr */ + $anr = $parentObjectInstance->getAnr(); + $this->anrInstanceService->instantiateObjectToAnr($anr, $instanceData); + } + } + + private function validateIfObjectOrItsChildrenLinkedToOneOfParents( + Entity\MonarcObject $childObject, + Entity\MonarcObject $parentObject + ): void { + if ($parentObject->isObjectOneOfParents($childObject)) { + throw new Exception('It\'s not allowed to make a composition with circular dependency.', 412); + } + + foreach ($childObject->getChildren() as $childOfChildObject) { + $this->validateIfObjectOrItsChildrenLinkedToOneOfParents($childOfChildObject, $parentObject); + } + } +} diff --git a/src/Service/AnrObjectService.php b/src/Service/AnrObjectService.php index 26d94322..0e423a85 100755 --- a/src/Service/AnrObjectService.php +++ b/src/Service/AnrObjectService.php @@ -1,336 +1,553 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } - // TODO: move all the import functionality to the ObjectImportService. + public function getList(FormattedInputParams $formattedInputParams): array + { + $result = []; + /** @var Entity\MonarcObject $object */ + foreach ($this->monarcObjectTable->findByParams($formattedInputParams) as $object) { + $result[] = $this->getPreparedObjectData($object); + } - /** - * Imports a previously exported object from an uploaded file into the current ANR. It may be imported using two - * different modes: 'merge', which will update the existing objects using the file's data, or 'duplicate' which - * will create a new object using the data. - * - * @param int $anrId The ANR ID - * @param array $data The data that has been posted to the API - * - * @return array An array where the first key is the generated IDs, and the second are import errors - * @throws Exception If the uploaded data is invalid, or the ANR invalid - */ - public function importFromFile($anrId, $data) + return $result; + } + + public function getCount(FormattedInputParams $formattedInputParams): int { - // Mode may either be 'merge' or 'duplicate' - $mode = empty($data['mode']) ? 'merge' : $data['mode']; + return $this->monarcObjectTable->countByParams($formattedInputParams, 'uuid'); + } - // We can have multiple files imported with the same password (we'll emit warnings if the password mismatches) - if (empty($data['file'])) { - throw new Exception('File missing', 412); - } + public function getObjectData(Entity\Anr $anr, string $uuid, FormattedInputParams $formattedInputParams): array + { + /** @var Entity\MonarcObject $object */ + $object = $this->monarcObjectTable->findByUuidAndAnr($uuid, $anr); - $ids = []; - $errors = []; - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - $anr = $anrTable->findById($anrId); - - foreach ($data['file'] as $f) { - // Ensure the file has been uploaded properly, silently skip the files that are erroneous - if (isset($f['error']) && $f['error'] === UPLOAD_ERR_OK && file_exists($f['tmp_name'])) { - if (empty($data['password'])) { - $file = json_decode(trim(file_get_contents($f['tmp_name'])), true); - if ($file === false) { // support legacy export which were base64 encoded - $file = json_decode( - trim($this->decrypt(base64_decode(file_get_contents($f['tmp_name'])), '')), - true - ); - } - } else { - // Decrypt the file and store the JSON data as an array in memory - $key = $data['password']; - $file = json_decode(trim($this->decrypt(file_get_contents($f['tmp_name']), $key)), true); - if ($file === false) { // support legacy export which were base64 encoded - $file = json_decode( - trim($this->decrypt(base64_decode(file_get_contents($f['tmp_name'])), $key)), - true - ); - } - } + $objectData = $this->getPreparedObjectData($object); + /* Object edit dialog scenario. */ + if (!$this->isAnrObjectMode($formattedInputParams->getFilter())) { + return $objectData; + } - /** @var ObjectImportService $objectImportService */ - $objectImportService = $this->get('objectImportService'); - $monarcObject = null; - if ($file !== false) { - $monarcObject = $objectImportService->importFromArray($file, $anr, $mode); - if ($monarcObject !== null) { - $ids[] = $monarcObject->getUuid(); - } - } - if ($monarcObject === null) { - $errors[] = 'The file "' . $f['name'] . '" can\'t be imported'; - } + $anrLanguage = $anr->getLanguage(); + $objectData['children'] = $this->getChildrenTreeList($object, $anrLanguage); + $objectData['risks'] = $this->getRisks($object, $anrLanguage); + $objectData['oprisks'] = $this->getRisksOp($object, $anrLanguage); + $objectData['parents'] = $this->getDirectParents($object, $anrLanguage); + + $instances = $this->instanceTable->findByAnrAndObject($anr, $object); + $objectData['replicas'] = []; + foreach ($instances as $instance) { + $instanceHierarchy = $instance->getHierarchyArray(); + + $names = [ + 'name' . $anrLanguage => $anr->getLabel(), + ]; + foreach ($instanceHierarchy as $instanceData) { + $names['name' . $anrLanguage] .= ' > ' . $instanceData['name' . $anrLanguage]; } + $names['id'] = $instance->getId(); + $objectData['replicas'][] = $names; } - return [$ids, $errors]; + return $objectData; } - /** - * Fetches and returns the list of objects from the common database. This will only return a limited set of fields, - * use {#getCommonEntity} to get the entire object definition. - * @see #getCommonEntity - * - * @param int $anrId The target ANR ID, $filter Keywords to search - * - * @return array An array of available objects from the common database (knowledge base) - * @throws Exception If the ANR ID is not set or invalid - */ - public function getCommonObjects($anrId, $filter = null) + public function getLibraryTreeStructure(Entity\Anr $anr): array { - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); + $result = []; + foreach ($this->objectCategoryTable->findRootCategoriesByAnrOrderedByPosition($anr) as $rootObjectCategory) { + $objectsCategoriesData = $this->getCategoriesAndObjectsTreeList($rootObjectCategory); + if (!empty($objectsCategoriesData)) { + $result[] = $objectsCategoriesData; + } } - $anr = $this->get('anrTable')->getEntity($anrId); // throws an Monarc\Core\Exception\Exception if unknown - - // Fetch the objects from the common database - $objects = $this->get('selfCoreService')->getAnrObjects( - 1, - -1, - 'name' . $anr->get('language'), - $filter, - null, - $anr->get('model'), - null, - AbstractEntity::FRONT_OFFICE - ); - - // List of fields we want to keep - $fields = [ - 'uuid', - 'mode', - 'scope', - 'name' . $anr->get('language'), - 'label' . $anr->get('language'), - 'disponibility', - 'position', - ]; - $fields = array_combine($fields, $fields); - - foreach ($objects as $k => $o) { - // Filter out the fields we don't want - foreach ($o as $k2 => $v2) { - if (!isset($fields[$k2])) { - unset($objects[$k][$k2]); - } + /* Places uncategorized objects. */ + $uncategorizedObjectsData = []; + foreach ($anr->getObjects() as $object) { + if (!$object->hasCategory()) { + $uncategorizedObjectsData[] = $this->getPreparedObjectData($object, true); } + } + if (!empty($uncategorizedObjectsData)) { + $result[] = CoreEntity\ObjectCategorySuperClass::getUndefinedCategoryData($uncategorizedObjectsData); + } - // Fetch the category details, if one is set - if ($o['category']) { - $objects[$k]['category'] = $o['category']->getJsonArray([ - 'id', - 'root', - 'parent', - 'label' . $anr->get('language'), - 'position', - ]); - } + return $result; + } - // Append the object to our array - $objects[$k]['asset'] = $o['asset']->getJsonArray([ - 'uuid', - 'label' . $anr->get('language'), - 'description' . $anr->get('language'), - 'mode', - 'type', - 'status', - ]); + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\MonarcObject + { + /** @var Entity\Asset $asset */ + $asset = $this->assetTable->findByUuidAndAnr($data['asset'], $anr); + $this->validateAssetAndDataOnCreate($asset, $data); + /** @var Entity\ObjectCategory $objectCategory */ + $objectCategory = $this->objectCategoryTable->findByIdAndAnr($data['category'], $anr); + /** @var ?Entity\RolfTag $rolfTag */ + $rolfTag = !empty($data['rolfTag']) && $asset->isPrimary() + ? $this->rolfTagTable->findByIdAndAnr($data['rolfTag'], $anr) + : null; + + return $this->createMonarcObject($anr, $asset, $objectCategory, $rolfTag, $data, $saveInDb); + } + + public function createMonarcObject( + Entity\Anr $anr, + Entity\Asset $asset, + ?Entity\ObjectCategory $objectCategory, + ?Entity\RolfTag $rolfTag, + array $data, + bool $saveInDb + ): Entity\MonarcObject { + $monarcObject = (new Entity\MonarcObject()) + ->setAnr($anr) + ->setLabels($data) + ->setNames($data) + ->setAsset($asset) + ->setCategory($objectCategory) + ->setScope($data['scope']) + ->setRolfTag($rolfTag) + ->setCreator($this->connectedUser->getEmail()); + if (!empty($data['uuid'])) { + $monarcObject->setUuid($data['uuid']); } - return $objects; + $this->monarcObjectTable->save($monarcObject, $saveInDb); + + return $monarcObject; } /** - * Fetches and returns the details of a specific object from the common database. - * - * @param int $anrId The target ANR ID - * @param int $id The common object ID - * - * @return Object The fetched object - * @throws Exception If the ANR is invalid, or the object ID is not found + * @return string[] */ - public function getCommonEntity($anrId, $id) + public function createList(Entity\Anr $anr, array $data): array + { + $createdObjectsUuids = []; + foreach ($data as $objectData) { + $object = $this->create($anr, $objectData, false); + $createdObjectsUuids[] = $object->getUuid(); + } + + return $createdObjectsUuids; + } + + public function update(Entity\Anr $anr, string $uuid, array $data): Entity\MonarcObject + { + /** @var Entity\MonarcObject $monarcObject */ + $monarcObject = $this->monarcObjectTable->findByUuidAndAnr($uuid, $anr); + $monarcObject + ->setLabels($data) + ->setNames($data) + ->setUpdater($this->connectedUser->getEmail()); + + if (!$monarcObject->hasCategory() || $monarcObject->getCategory()->getId() !== $data['category']) { + /** @var Entity\ObjectCategory $category */ + $category = $this->objectCategoryTable->findById((int)$data['category']); + $monarcObject->setCategory($category); + } + + $this->adjustInstancesValidateAndSetRolfTag($monarcObject, $data); + + $this->monarcObjectTable->save($monarcObject); + + return $monarcObject; + } + + public function duplicate(Entity\Anr $anr, array $data): Entity\MonarcObject { - if (empty($anrId)) { - throw new Exception('Anr id missing', 412); + /** @var Entity\MonarcObject $monarcObjectToCopy */ + $monarcObjectToCopy = $this->monarcObjectTable->findByUuidAndAnr($data['id'], $anr); + + $newMonarcObject = $this->getObjectCopy($monarcObjectToCopy, $anr); + + $this->duplicateObjectChildren($monarcObjectToCopy, $newMonarcObject, $anr); + + $this->monarcObjectTable->save($newMonarcObject); + + return $newMonarcObject; + } + + public function delete(Entity\Anr $anr, string $uuid): void + { + /** @var Entity\MonarcObject $monarcObject */ + $monarcObject = $this->monarcObjectTable->findByUuidAndAnr($uuid, $anr); + + /* Remove from the library object composition (affects all the linked analysis), shift positions. */ + foreach ($monarcObject->getParentsLinks() as $objectParentLink) { + $this->shiftPositionsForRemovingEntity($objectParentLink, $this->objectObjectTable); + $this->objectObjectTable->remove($objectParentLink, false); } - /** @var Anr $anr */ - $anr = $this->get('anrTable')->getEntity($anrId); // on a une erreur si inconnue + /* Remove the directly linked instances and shift their positions. */ + foreach ($monarcObject->getInstances() as $instance) { + $this->shiftPositionsForRemovingEntity($instance, $this->instanceTable); + $instance->removeAllInstanceRisks()->removeAllOperationalInstanceRisks(); + $monarcObject->removeInstance($instance); + $this->instanceTable->remove($instance, false); + } + + /* Manage the positions shift for the objects and objects_objects tables. */ + foreach ($monarcObject->getParentsLinks() as $linkWhereTheObjectIsChild) { + $this->shiftPositionsForRemovingEntity($linkWhereTheObjectIsChild, $this->objectObjectTable); + } + + $this->monarcObjectTable->remove($monarcObject); + } + + public function getParentsInAnr(Entity\Anr $anr, string $uuid) + { + /** @var Entity\MonarcObject $object */ + $object = $this->monarcObjectTable->findByUuidAndAnr($uuid, $anr); + $anrLanguage = $anr->getLanguage(); - $object = current($this->get('selfCoreService')->getAnrObjects( - 1, - -1, - 'name' . $anrLanguage, - [], - ['uuid' => $id], - $anr->getModel(), - null, - AbstractEntity::FRONT_OFFICE - )); - if (empty($object)) { - throw new Exception('Object not found', 412); + $directParents = []; + foreach ($object->getParentsLinks() as $parentLink) { + $directParents = [ + 'uuid' => $parentLink->getParent()->getUuid(), + 'linkid' => $parentLink->getId(), + 'label' . $anrLanguage => $parentLink->getParent()->getLabel($anrLanguage), + 'name' . $anrLanguage => $parentLink->getParent()->getName($anrLanguage), + ]; } - $objectData = $this->get('selfCoreService')->getCompleteEntity($id); - /** @var AssetSuperClass $asset */ - $asset = $object['asset']; - $object['asset'] = [ - 'uuid' => $asset->getUuid(), - 'code' => $asset->getCode(), - 'label' . $anrLanguage => $asset->getLabel($anrLanguage), - 'description' . $anrLanguage => $asset->getDescription($anrLanguage), - 'type' => $asset->getType(), - 'mode' => $asset->getMode(), + return $directParents; + } + + private function validateAssetAndDataOnCreate(Entity\Asset $asset, array $data): void + { + if ($data['scope'] === CoreEntity\ObjectSuperClass::SCOPE_GLOBAL && $asset->isPrimary()) { + throw new Exception('It is forbidden to create a global object linked to a primary asset', 412); + } + } + + private function getPreparedObjectData(Entity\MonarcObject $object, bool $objectOnly = false): array + { + $anr = $object->getAnr(); + $result = [ + 'uuid' => $object->getUuid(), + 'label' . $anr->getLanguage() => $object->getLabel($anr->getLanguage()), + 'name' . $anr->getLanguage() => $object->getName($anr->getLanguage()), + 'scope' => $object->getScope(), ]; - if (!empty($object['category'])) { - /** @var ObjectCategorySuperClass $objectCategory */ - $objectCategory = $objectData['category']; - $objectData['category'] = [ - 'id' => $objectCategory->getId(), - 'label' . $anrLanguage => $objectCategory->getLabel($anrLanguage), - 'root' => $objectCategory->getRoot() !== null ? $objectCategory->getRoot()->getId() : null, - 'parent' => $objectCategory->getParent() !== null ? $objectCategory->getParent()->getId() : null, + + if (!$objectOnly) { + $result['category'] = $object->getCategory() !== null + ? [ + 'id' => $object->getCategory()->getId(), + 'position' => $object->getCategory()->getPosition(), + 'label' . $anr->getLanguage() => $object->getCategory()->getLabel($anr->getLanguage()), + ] + : CoreEntity\ObjectCategorySuperClass::getUndefinedCategoryData([]); + $result['asset'] = [ + 'uuid' => $object->getAsset()->getUuid(), + 'label' . $anr->getLanguage() => $object->getAsset()->getLabel($anr->getLanguage()), + 'code' => $object->getAsset()->getCode(), + 'type' => $object->getAsset()->getType(), + 'mode' => $object->getAsset()->getMode(), + ]; + $result['rolfTag'] = $object->getRolfTag() === null ? null : [ + 'id' => $object->getRolfTag()->getId(), + 'code' => $object->getRolfTag()->getCode(), + 'label' . $anr->getLanguage() => $object->getRolfTag()->getLabel($anr->getLanguage()), ]; } - if (!empty($object['rolfTag'])) { - /** @var RolfTagSuperClass $rolfTag */ - $rolfTag = $objectData['rolfTag']; - $objectData['rolfTag'] = [ - 'id' => $rolfTag->getId(), - 'code' => $rolfTag->getCode(), - 'label' . $anrLanguage => $rolfTag->getLabel($anrLanguage), + + return $result; + } + + private function isAnrObjectMode(array $filteredData): bool + { + return isset($filteredData['mode']['value']) && $filteredData['mode']['value'] === 'anr'; + } + + private function getChildrenTreeList(Entity\MonarcObject $object, int $anrLanguage): array + { + $result = []; + foreach ($object->getChildrenLinks() as $childLinkObject) { + /** @var Entity\MonarcObject $childMonarcObject */ + $childMonarcObject = $childLinkObject->getChild(); + $result[] = [ + 'uuid' => $childMonarcObject->getUuid(), + 'label' . $anrLanguage => $childMonarcObject->getLabel($anrLanguage), + 'name' . $anrLanguage => $childMonarcObject->getName($anrLanguage), + 'component_link_id' => $childLinkObject->getId(), + 'mode' => $childMonarcObject->getMode(), + 'scope' => $childMonarcObject->getScope(), + 'children' => !$childMonarcObject->hasChildren() + ? [] + : $this->getChildrenTreeList($childMonarcObject, $anrLanguage), ]; } - unset($object['anrs']); + return $result; + } + + private function getRisks(Entity\MonarcObject $object, int $anrLanguage): array + { + $risks = []; + foreach ($object->getAsset()->getAmvs() as $amv) { + $risks[] = [ + 'id' => $amv->getUuid(), + 'threatLabel' . $anrLanguage => $amv->getThreat()->getLabel($anrLanguage), + 'threatDescription' . $anrLanguage => $amv->getThreat()->getDescription($anrLanguage), + 'threatRate' => '-', + 'vulnLabel' . $anrLanguage => $amv->getVulnerability()->getLabel($anrLanguage), + 'vulnDescription' . $anrLanguage => $amv->getVulnerability()->getDescription($anrLanguage), + 'vulnerabilityRate' => '-', + 'c_risk' => '-', + 'c_risk_enabled' => $amv->getThreat()->getConfidentiality(), + 'i_risk' => '-', + 'i_risk_enabled' => $amv->getThreat()->getIntegrity(), + 'd_risk' => '-', + 'd_risk_enabled' => $amv->getThreat()->getAvailability(), + 'comment' => '', + ]; + } - return $objectData; + return $risks; } - /** - * Imports an object from the common database into the specified ANR. The ANR id must be set in $data['anr']. - * - * @param int $id The common object ID - * @param array $data An array with ['anr' => 'The anr id', 'mode' => 'merge or duplicate'] - * - * @throws Exception If the ANR is invalid, or the object ID is not found - */ - public function importFromCommon($id, $data): ?MonarcObject + private function getRisksOp(Entity\MonarcObject $object, int $anrLanguage): array { - if (empty($data['anr'])) { - throw new Exception('Anr id missing', 412); + $riskOps = []; + if ($object->getRolfTag() !== null && $object->getAsset()->isPrimary()) { + foreach ($object->getRolfTag()->getRisks() as $rolfRisk) { + $riskOps[] = [ + 'label' . $anrLanguage => $rolfRisk->getLabel($anrLanguage), + 'description' . $anrLanguage => $rolfRisk->getDescription($anrLanguage), + ]; + } } - $anr = $this->get('anrTable')->getEntity($data['anr']); // on a une erreur si inconnue - $object = current($this->get('selfCoreService')->getAnrObjects( - 1, - -1, - 'name' . $anr->get('language'), - [], - ['uuid' => $id], - $anr->get('model'), - null, - AbstractEntity::FRONT_OFFICE - )); - if (empty($object)) { - throw new Exception('Object not found', 412); + + return $riskOps; + } + + private function getDirectParents(Entity\MonarcObject $object, int $anrLanguage): array + { + $parents = []; + foreach ($object->getParents() as $parentObject) { + $parents[] = [ + 'name' . $anrLanguage => $parentObject->getName($anrLanguage), + 'label' . $anrLanguage => $parentObject->getLabel($anrLanguage), + ]; } - // Export - $json = $this->get('selfCoreService')->get('objectExportService')->generateExportArray($id); - if ($json) { - /** @var ObjectImportService $objectImportService */ - $objectImportService = $this->get('objectImportService'); + return $parents; + } - return $objectImportService->importFromArray($json, $anr, isset($data['mode']) ? $data['mode'] : 'merge'); + private function adjustInstancesValidateAndSetRolfTag(Entity\MonarcObject $monarcObject, array $data): void + { + /* Set operational risks to specific only when RolfTag was set before, and another RolfTag or null is set. */ + $isRolfTagUpdated = false; + 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); + + /* A new RolfTag is linked, set all linked operational risks to specific, new risks should be created. */ + $isRolfTagUpdated = true; + } elseif (empty($data['rolfTag']) && $monarcObject->getRolfTag() !== null) { + $monarcObject->setRolfTag(null); + + /* Set all linked operational risks to specific, no new risks to create. */ + $isRolfTagUpdated = true; } - return null; + $this->updateInstancesAndOperationalRisks($monarcObject, $isRolfTagUpdated); } - public function export(&$data) + private function updateInstancesAndOperationalRisks(Entity\MonarcObject $monarcObject, bool $isRolfTagUpdated): void { - if (empty($data['id'])) { - throw new Exception('Object to export is required', 412); + foreach ($monarcObject->getInstances() as $instance) { + $instance->setNames($monarcObject->getNames()) + ->setLabels($monarcObject->getLabels()); + $this->instanceTable->save($instance, false); + + if (!$monarcObject->getAsset()->isPrimary()) { + continue; + } + + $rolfRisksIdsToOperationalInstanceRisks = []; + foreach ($instance->getOperationalInstanceRisks() as $operationalInstanceRisk) { + $rolfRiskId = $operationalInstanceRisk->getRolfRisk()->getId(); + $rolfRisksIdsToOperationalInstanceRisks[$rolfRiskId] = $operationalInstanceRisk; + if ($isRolfTagUpdated) { + /* If the tag is updated, the existing operational risks have to become specific. */ + $operationalInstanceRisk->setIsSpecific(true); + $this->instanceRiskOpTable->save($operationalInstanceRisk, false); + } + } + + if ($isRolfTagUpdated && $monarcObject->getRolfTag() !== null) { + foreach ($monarcObject->getRolfTag()->getRisks() as $rolfRisk) { + if (isset($rolfRisksIdsToOperationalInstanceRisks[$rolfRisk->getId()])) { + /* Restore the specific to false if the operational risk is linked to another risk. */ + $rolfRisksIdsToOperationalInstanceRisks[$rolfRisk->getId()]->setIsSpecific(false); + $this->instanceRiskOpTable->save( + $rolfRisksIdsToOperationalInstanceRisks[$rolfRisk->getId()], + false + ); + } else { + /* Recreate the risk with scales if it did not exist before. */ + $this->anrInstanceRiskOpService->createInstanceRiskOpWithScales( + $instance, + $monarcObject, + $rolfRisk + ); + } + } + } } + } - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - $anr = $anrTable->findById($data['anr']); + private function getObjectCopy(Entity\MonarcObject $monarcObjectToCopy, Entity\Anr $anr): Entity\MonarcObject + { + $labelsNamesSuffix = ' copy #' . time(); + /** @var Entity\MonarcObject $newMonarcObject */ + $newMonarcObject = (new Entity\MonarcObject()) + ->setAnr($anr) + ->setCategory($monarcObjectToCopy->getCategory()) + ->setAsset($monarcObjectToCopy->getAsset()) + ->setLabels([ + 'label1' => $monarcObjectToCopy->getLabelCleanedFromCopy(1) . $labelsNamesSuffix, + 'label2' => $monarcObjectToCopy->getLabelCleanedFromCopy(2) . $labelsNamesSuffix, + 'label3' => $monarcObjectToCopy->getLabelCleanedFromCopy(3) . $labelsNamesSuffix, + 'label4' => $monarcObjectToCopy->getLabelCleanedFromCopy(4) . $labelsNamesSuffix, + ]) + ->setNames([ + 'name1' => $monarcObjectToCopy->getNameCleanedFromCopy(1) . $labelsNamesSuffix, + 'name2' => $monarcObjectToCopy->getNameCleanedFromCopy(2) . $labelsNamesSuffix, + 'name3' => $monarcObjectToCopy->getNameCleanedFromCopy(3) . $labelsNamesSuffix, + 'name4' => $monarcObjectToCopy->getNameCleanedFromCopy(4) . $labelsNamesSuffix, + ]) + ->setScope($monarcObjectToCopy->getScope()) + ->setCreator($this->connectedUser->getEmail()); + if ($monarcObjectToCopy->hasRolfTag()) { + $newMonarcObject->setRolfTag($monarcObjectToCopy->getRolfTag()); + } - /** @var ObjectExportService $objectExportService */ - $objectExportService = $this->get('objectExportService'); + return $newMonarcObject; + } - $isForMosp = !empty($data['mosp']); + private function duplicateObjectChildren( + Entity\MonarcObject $objectToCopy, + Entity\MonarcObject $parentObject, + Entity\Anr $anr + ): void { + foreach ($objectToCopy->getChildren() as $childObject) { + $newChildObject = $this->getObjectCopy($childObject, $anr); + + /* Only to keep the same positions in the duplicated object composition. */ + foreach ($childObject->getParentsLinks() as $parentLink) { + /* The child object could be presented in different compositions, so validate if the parent is right. */ + if ($parentLink->getParent()->isEqualTo($objectToCopy)) { + $newParentLink = (new Entity\ObjectObject()) + ->setAnr($anr) + ->setParent($parentObject) + ->setChild($newChildObject) + ->setPosition($parentLink->getPosition()) + ->setCreator($this->connectedUser->getEmail()); + $this->objectObjectTable->save($newParentLink, false); + + $newChildObject->addParentLink($newParentLink); + } + } - $prepareObjectData = json_encode($isForMosp - ? $objectExportService->generateExportMospArray($data['id'], $anr) - : $objectExportService->generateExportArray($data['id'], $anr)); + $this->monarcObjectTable->save($newChildObject, false); - $data['filename'] = $objectExportService->generateExportFileName($data['id'], $anr, $isForMosp); + if ($childObject->hasChildren()) { + $this->duplicateObjectChildren($childObject, $newChildObject, $anr); + } + } + } - if (!empty($data['password'])) { - $prepareObjectData = $this->encrypt($prepareObjectData, $data['password']); + private function getPreparedObjectCategoryData(Entity\ObjectCategory $category, array $objectsData): array + { + $result = [ + 'id' => $category->getId(), + 'label' . $category->getAnr()->getLanguage() => $category->getLabel($category->getAnr()->getLanguage()), + 'position' => $category->getPosition(), + 'child' => !$category->hasChildren() ? [] : $this->getCategoriesWithObjectsChildrenTreeList($category), + 'objects' => $objectsData, + ]; + if (empty($objectsData) && empty($result['child'])) { + return []; } - return $prepareObjectData; + return $result; } - /** - * @param array $data - * @param AnrSuperClass|null $anr The nullable value possibility is to comply with the core definition. - * - * @return ObjectSuperClass|null - * - * @throws NonUniqueResultException - */ - protected function importFromMosp(array $data, ?AnrSuperClass $anr): ?ObjectSuperClass + private function getCategoriesAndObjectsTreeList(Entity\ObjectCategory $objectCategory): array + { + $result = []; + $objectsData = $this->getObjectsDataOfCategory($objectCategory); + if (!empty($objectsData) || $objectCategory->hasChildren()) { + $objectCategoryData = $this->getPreparedObjectCategoryData($objectCategory, $objectsData); + if (!empty($objectsData) || !empty($objectCategoryData)) { + $result = $objectCategoryData; + } + } + + return $result; + } + + private function getCategoriesWithObjectsChildrenTreeList(Entity\ObjectCategory $objectCategory): array { - if ($anr === null) { - return null; + $result = []; + foreach ($objectCategory->getChildren() as $childCategory) { + $categoryData = $this->getCategoriesAndObjectsTreeList($childCategory); + if (!empty($categoryData)) { + $result[] = $categoryData; + } } - /** @var ObjectImportService $objectImportService */ - $objectImportService = $this->get('objectImportService'); + return $result; + } + + private function getObjectsDataOfCategory(Entity\ObjectCategory $objectCategory): array + { + $objectsData = []; + /** @var Entity\MonarcObject $object */ + foreach ($objectCategory->getObjects() as $object) { + $objectsData[] = $this->getPreparedObjectData($object, true); + } - return $objectImportService->importFromArray($data, $anr, $data['mode'] ?? 'merge'); + return $objectsData; } } diff --git a/src/Service/AnrObjectServiceFactory.php b/src/Service/AnrObjectServiceFactory.php deleted file mode 100755 index 9111423a..00000000 --- a/src/Service/AnrObjectServiceFactory.php +++ /dev/null @@ -1,42 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\MonarcObjectTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\MonarcObject', - 'anrObjectCategoryEntity' => 'Monarc\FrontOffice\Model\Entity\AnrObjectCategory', - 'assetTable' => 'Monarc\FrontOffice\Model\Table\AssetTable', - 'assetService' => 'Monarc\FrontOffice\Service\AnrAssetService', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrObjectCategoryTable' => 'Monarc\FrontOffice\Model\Table\AnrObjectCategoryTable', - 'amvTable' => 'Monarc\FrontOffice\Model\Table\AmvTable', - 'categoryTable' => 'Monarc\FrontOffice\Model\Table\ObjectCategoryTable', - 'instanceTable' => 'Monarc\FrontOffice\Model\Table\InstanceTable', - 'modelTable' => 'Monarc\Core\Model\Table\ModelTable', - 'objectObjectTable' => 'Monarc\FrontOffice\Model\Table\ObjectObjectTable', - 'rolfTagTable' => 'Monarc\FrontOffice\Model\Table\RolfTagTable', - 'modelService' => 'Monarc\Core\Service\ModelService', - 'objectObjectService' => 'Monarc\FrontOffice\Service\ObjectObjectService', - 'objectExportService' => 'Monarc\FrontOffice\Service\ObjectExportService', - 'objectImportService' => ObjectImportService::class, - 'selfCoreService' => 'Monarc\Core\Service\ObjectService', - 'instanceRiskOpTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskOpTable', - 'instanceRiskOpService' => 'Monarc\FrontOffice\Service\AnrInstanceRiskOpService', - ]; -} diff --git a/src/Service/AnrQuestionChoiceServiceFactory.php b/src/Service/AnrQuestionChoiceServiceFactory.php index 8fe951de..7ea2b4f5 100755 --- a/src/Service/AnrQuestionChoiceServiceFactory.php +++ b/src/Service/AnrQuestionChoiceServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Proxy class to instantiate Monarc\Core's QuestionChoiceService, with Monarc\FrontOffice's services @@ -19,9 +21,9 @@ class AnrQuestionChoiceServiceFactory extends AbstractServiceFactory protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\QuestionChoiceTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\QuestionChoice', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', + 'entity' => 'Monarc\FrontOffice\Entity\QuestionChoice', + 'anrTable' => AnrTable::class, + 'userAnrTable' => UserAnrTable::class, 'questionTable' => 'Monarc\FrontOffice\Model\Table\QuestionTable', ]; } diff --git a/src/Service/AnrQuestionServiceFactory.php b/src/Service/AnrQuestionServiceFactory.php index e311ee56..72d18038 100755 --- a/src/Service/AnrQuestionServiceFactory.php +++ b/src/Service/AnrQuestionServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Proxy class to instantiate Monarc\Core's QuestionService, with Monarc\FrontOffice's services @@ -19,9 +21,9 @@ class AnrQuestionServiceFactory extends AbstractServiceFactory protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\QuestionTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Question', + 'entity' => 'Monarc\FrontOffice\Entity\Question', 'choiceTable' => 'Monarc\FrontOffice\Model\Table\QuestionChoiceTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', + 'anrTable' => AnrTable::class, + 'userAnrTable' => UserAnrTable::class, ]; } diff --git a/src/Service/AnrRecommandationHistoricService.php b/src/Service/AnrRecommandationHistoricService.php deleted file mode 100755 index 0af5ce61..00000000 --- a/src/Service/AnrRecommandationHistoricService.php +++ /dev/null @@ -1,22 +0,0 @@ - RecommandationHistoric::class, - 'table' => Table\RecommendationHistoricTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - ]; -} diff --git a/src/Service/AnrRecommandationRiskService.php b/src/Service/AnrRecommandationRiskService.php deleted file mode 100755 index c80ee136..00000000 --- a/src/Service/AnrRecommandationRiskService.php +++ /dev/null @@ -1,815 +0,0 @@ -get('entity')->getFiltersForService(); - /** @var Table\RecommandationRiskTable $table */ - $table = $this->get('table'); - $recosRisks = $table->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd, - $filterJoin, - $filterLeft - ); - - foreach ($recosRisks as $key => $recoRisk) { - if (!empty($recoRisk['recommandation'])) { - if (empty($recoRisk['recommandation']->duedate) || $recoRisk['recommandation']->duedate == '1970-01-01 00:00:00') { - } else { - if ($recoRisk['recommandation']->duedate instanceof \DateTime) { - $recoRisk['recommandation']->duedate = $recoRisk['recommandation']->duedate->getTimestamp(); - } else { - $recoRisk['recommandation']->duedate = strtotime($recoRisk['recommandation']->duedate); - } - $recoRisk['recommandation']->duedate = date('d-m-Y', $recoRisk['recommandation']->duedate); - } - - $recoRisk['recommandation']->recommandationSet->anr = $recoRisk['anr']->id; - $recosRisks[$key]['recommandation'] = $recoRisk['recommandation']; - } - } - - // Filter out duplicate global objects - $knownGlobObjId = $objectCache = []; - - if (isset($filterAnd['r.uuid']) && isset($filterAnd['r.anr'])) { - return array_filter($recosRisks, function ($recoRisk) use (&$knownGlobObjId, &$objectCache) { - $vulnerability = $recoRisk['vulnerability']; - $threat = $recoRisk['threat']; - if ($recoRisk['instanceRiskOp'] instanceof InstanceRiskOp - || $vulnerability === null - || $threat === null - ) { - return true; - } - - /** @var Instance $instance */ - $instance = $this->instanceTable->getEntity($recoRisk['instance']); - $objId = $instance->getObject()->getUuid(); - - if (!isset($knownGlobObjId[$objId][$threat->getUuid()][$vulnerability->getUuid()])) { - $objectCache[$objId] = $instance->getObject(); - if ($objectCache[$objId]->isScopeGlobal()) { - $knownGlobObjId[$objId][$threat->getUuid()][$vulnerability->getUuid()] = $objId; - } - - return true; - } - - return false; - }); - } - - return $recosRisks; - } - - /** - * @throws EntityNotFoundException - * @throws Exception - * @throws OptimisticLockException - */ - public function delete($id) - { - /** @var Table\RecommandationRiskTable $recommendationRiskTable */ - $recommendationRiskTable = $this->get('table'); - $recommendationRisk = $recommendationRiskTable->findById($id); - $recommendation = $recommendationRisk->getRecommandation(); - - if ($recommendationRisk->getInstanceRisk() !== null) { - $instanceRisk = $recommendationRisk->getInstanceRisk(); - - if ($instanceRisk->getInstance()->getObject()->getScope() === MonarcObject::SCOPE_GLOBAL) { - if ($instanceRisk->getAmv() === null && $instanceRisk->isSpecific()) {//case specific amv_id = null - $brothers = $this->instanceRiskTable->getEntityByFields([ - 'asset' => [ - 'anr' => $instanceRisk->getAnr()->getId(), - 'uuid' => $instanceRisk->getAsset()->getUuid(), - ], - 'threat' => [ - 'anr' => $instanceRisk->getAnr()->getId(), - 'uuid' => $instanceRisk->getThreat()->getUuid(), - ], - 'vulnerability' => [ - 'anr' => $instanceRisk->getAnr()->getId(), - 'uuid' => $instanceRisk->getVulnerability()->getUuid(), - ], - ]); - } else { - $brothers = $this->instanceRiskTable->findByAmv($instanceRisk->getAmv()); - } - $brothersIds = []; - foreach ($brothers as $brother) { - if ($instanceRisk->getInstance()->getObject()->isEqualTo($brother->getInstance()->getObject())) { - $brothersIds[] = $brother->getId(); - } - } - - foreach ($recommendation->getRecommendationRisks() as $recommendationRiskRelatedToReco) { - if ($recommendationRiskRelatedToReco->getInstanceRisk() - && \in_array($recommendationRiskRelatedToReco->getInstanceRisk()->getId(), $brothersIds, true) - ) { - $recommendationRiskTable->deleteEntity($recommendationRiskRelatedToReco); - } - } - } else { - $recommendationRiskTable->deleteEntity($recommendationRisk); - } - } else { - $instanceRiskOp = $recommendationRisk->getInstanceRiskOp(); - - if ($instanceRiskOp->getObject()->get('scope') === MonarcObject::SCOPE_GLOBAL) { - $brothers = $this->instanceRiskOpTable->getEntityByFields([ - 'anr' => $recommendationRisk->getInstanceRiskOp()->getAnr()->getId(), - 'rolfRisk' => $recommendationRisk->getInstanceRiskOp()->getRolfRisk()->getId(), - ]); - $brothersIds = []; - foreach ($brothers as $brother) { - if ($instanceRiskOp->getInstance()->getObject()->isEqualTo($brother->getInstance()->getObject())) { - $brothersIds[] = $brother->id; - } - } - - foreach ($recommendation->getRecommendationRisks() as $recommendationRiskRelatedToReco) { - if ($recommendationRiskRelatedToReco->getInstanceRiskOp() - && \in_array($recommendationRiskRelatedToReco->getInstanceRiskOp()->getId(), $brothersIds, true) - ) { - $recommendationRiskTable->deleteEntity($recommendationRiskRelatedToReco); - } - } - } else { - $recommendationRiskTable->deleteEntity($recommendationRisk); - } - } - - // Reset the recommendation's position if it's not linked to risks anymore. - if (!$recommendation->hasLinkedRecommendationRisks()) { - $this->resetRecommendationsPositions( - $recommendation->getAnr(), - [$recommendation->getUuid() => $recommendation] - ); - } - } - - /** - * @inheritdoc - */ - public function create($data, $last = true) - { - //verify not already exist - /** @var Table\RecommandationRiskTable $table */ - $table = $this->get('table'); - if ($data['op']) { - $exist = $table->getEntityByFields([ - 'anr' => $data['anr'], - 'recommandation' => ['anr' => $data['anr'], 'uuid' => $data['recommandation']], - 'instanceRiskOp' => $data['risk'] - ]); - $tableUsed = $this->instanceRiskOpTable; - } else { - $exist = $table->getEntityByFields([ - 'anr' => $data['anr'], - 'recommandation' => ['anr' => $data['anr'], 'uuid' => $data['recommandation']], - 'instanceRisk' => $data['risk'] - ]); - $tableUsed = $this->instanceRiskTable; - } - if (count($exist)) { - throw new Exception('Risk already link to this recommendation', 412); - } - - $gRisk = $tableUsed->getEntity($data['risk']); - $id = $this->createRecommandationRisk($data, $gRisk); - if ($gRisk->getInstance()->getObject()->get('scope') == MonarcObject::SCOPE_GLOBAL && !$data['op']) { - - $instances = $this->instanceTable->getEntityByFields([ - 'object' => [ - 'anr' => $gRisk->anr->id, - 'uuid' => $gRisk->getInstance()->getObject()->getUuid() - ], - 'anr' => $gRisk->anr->id, - 'id' => ['op' => '!=', 'value' => $gRisk->getInstance()->get('id')], - ]); - $instanceIds = []; - foreach ($instances as $i) { - $instanceIds[$i->get('id')] = $i->get('id'); - } - - if (!empty($instanceIds)) { - $brothers = $tableUsed->getEntityByFields([ - 'asset' => ['anr' => $gRisk->getAnr()->getId(), 'uuid' => $gRisk->getAsset()->getUuid()], - 'threat' => ['anr' => $gRisk->getAnr()->getId(), 'uuid' => $gRisk->getThreat()->getUuid()], - 'vulnerability' => ['anr' => $gRisk->getAnr()->getId(), 'uuid' => $gRisk->getVulnerability()->getUuid()], - 'instance' => ['op' => 'IN', 'value' => $instanceIds], - 'anr' => $gRisk->getAnr()->getId() - ]); - - foreach ($brothers as $brother) { - $this->createRecommandationRisk($data, $brother); - } - } - } - - $this->updateInstanceRiskRecommendationsPositions($gRisk); - - return $id; - } - - public function getTreatmentPlan(int $anrId, string $uuid = null): array - { - $anr = $this->anrTable->findById($anrId); - - if ($uuid !== null) { - $recommendation = $this->recommendationTable->findByAnrAndUuid($anr, $uuid); - $linkedRecommendations = $recommendation === null ? [] : [$recommendation]; - } else { - $linkedRecommendations = $this->recommendationTable - ->findLinkedWithRisksByAnrWithSpecifiedImportanceAndPositionAndExcludeRecommendations( - $anr, - [], - ['r.position' => 'ASC'] - ); - } - - $treatmentPlan = []; - foreach ($linkedRecommendations as $linkedRecommendation) { - $instanceRisks = []; - $globalObjects = []; - foreach ($linkedRecommendation->getRecommendationRisks() as $index => $recommendationRisk) { - $instanceRisk = $recommendationRisk->getInstanceRisk(); - $type = 'risks'; - if ($instanceRisk === null) { - $instanceRisk = $recommendationRisk->getInstanceRiskOp(); - $type = 'risksop'; - } - - if ($type === 'risks' && $recommendationRisk->hasGlobalObjectRelation()) { - $path = $recommendationRisk->getInstance()->{'getName' . $anr->getLanguage()}(); - - $globalObjectUuid = $recommendationRisk->getGlobalObject()->getUuid(); - $assetUuid = $recommendationRisk->getAsset()->getUuid(); - $threatUuid = $recommendationRisk->getThreat()->getUuid(); - $vulnerabilityUuid = $recommendationRisk->getVulnerability()->getUuid(); - if (!empty($globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid])) { - if ($globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid]['maxRisk'] - < $instanceRisk->getCacheMaxRisk() - ) { - $globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid]['maxRisk'] = - $instanceRisk->getCacheMaxRisk(); - $ind = - $globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid]['index']; - $instanceRisks[$type][$ind] = array_merge($instanceRisk->getJsonArray(), [ - 'path' => $path, - 'isGlobal' => true, - ]); - } - - continue; - } - - $globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid] = [ - 'index' => $index, - 'maxRisk' => $instanceRisk->getCacheMaxRisk(), - ]; - } else { - $path = $instanceRisk->getInstance()->getHierarchyString(); - } - - $instanceRisks[$type][$index] = array_merge($instanceRisk->getJsonArray(), [ - 'path' => $path, - 'isGlobal' => $recommendationRisk->hasGlobalObjectRelation(), - ]); - // TODO: add only required fields instead of getJsonArray. - unset( - $instanceRisks[$type][$index]['__initializer__'], - $instanceRisks[$type][$index]['__cloner__'], - $instanceRisks[$type][$index]['__isInitialized__'], - $instanceRisks[$type][$index]['instance'], - $instanceRisks[$type][$index]['amv'], - $instanceRisks[$type][$index]['anr'], - $instanceRisks[$type][$index]['asset'], - $instanceRisks[$type][$index]['threat'], - $instanceRisks[$type][$index]['vulnerability'] - ); - } - - $treatmentPlan[] = array_merge([ - 'uuid' => $linkedRecommendation->getUuid(), - 'code' => $linkedRecommendation->getCode(), - 'description' => $linkedRecommendation->getDescription(), - 'importance' => $linkedRecommendation->getImportance(), - 'position' => $linkedRecommendation->getPosition(), - 'comment' => $linkedRecommendation->getComment(), - 'status' => $linkedRecommendation->getStatus(), - 'responsable' => $linkedRecommendation->getResponsable(), - 'duedate' => $linkedRecommendation->getDueDate() !== null - ? $linkedRecommendation->getDueDate()->format('Y-m-d') - : '', - 'counterTreated' => $linkedRecommendation->getCounterTreated(), - ], $instanceRisks); - } - - return $treatmentPlan; - } - - /** - * Creates a new recommendation for the provided risk - * - * @param array $data The data from the API - * @param InstanceRisk|InstanceRiskOp $risk The target risk or OP risk - * - * @return RecommandationRisk The created/saved recommendation risk - */ - public function createRecommandationRisk($data, $risk) - { - /** @var Table\RecommandationRiskTable $table */ - $table = $this->get('table'); - - $class = $this->get('entity'); - $entity = new $class(); - $entity->set('anr', $risk->anr); - $entity->setLanguage($this->getLanguage()); - $entity->setDbAdapter($this->get('table')->getDb()); - $entity->exchangeArray($data); - - $dependencies = (property_exists($this, 'dependencies')) ? $this->dependencies : []; - $this->setDependencies($entity, $dependencies); - if ($data['op']) { - $entity->setInstanceRisk(null); - $entity->setInstanceRiskOp($risk); - $entity->setAnr(null); - $table->save($entity); - $entity->set('anr', $risk->anr); //TO IMPROVE double save to have the correct anr_id with risk op - } else { - $entity->setInstanceRisk($risk); - $entity->setInstanceRiskOp(null); - - $entity->setAsset($risk->getAsset()); - $entity->setThreat($risk->getThreat()); - $entity->setVulnerability($risk->getVulnerability()); - } - - $entity->setInstance($risk->getInstance()); - if ($risk->getInstance()->getObject()->get('scope') == MonarcObject::SCOPE_GLOBAL) { - $entity->setGlobalObject($risk->getInstance()->getObject()); - } - - return $table->save($entity); - } - - /** - * @throws EntityNotFoundException - * @throws OptimisticLockException - */ - public function resetRecommendationsPositionsToDefault(int $anrId): void - { - $anr = $this->anrTable->findById($anrId); - - /** @var Table\RecommandationRiskTable $recommendationRiskTable */ - $recommendationRiskTable = $this->get('table'); - $recommendationRisks = $recommendationRiskTable->findByAnr($anr, ['r.importance' => 'DESC', 'r.code' => 'ASC']); - - $position = 1; - $updatedRecommendationsUuid = []; - foreach ($recommendationRisks as $recommendationRisk) { - $recommendation = $recommendationRisk->getRecommandation(); - if (!isset($updatedRecommendationsUuid[$recommendation->getUuid()])) { - $this->recommendationTable->saveEntity($recommendation->setPosition($position++), false); - $updatedRecommendationsUuid[$recommendation->getUuid()] = true; - } - } - $this->recommendationTable->getDb()->flush(); - } - - /** - * Validates a recommendation risk. Operational risks may not be validated, and will throw an error. - */ - public function validateFor(int $recommendationRiskId, array $data): void - { - /** @var Table\RecommandationRiskTable $recommendationRiskTable */ - $recommendationRiskTable = $this->get('table'); - $recommendationRisk = $recommendationRiskTable->findById($recommendationRiskId); - - // validate for operational risks - if ($recommendationRisk->getInstanceRiskOp() !== null) { - // Verify if recommendation risk is final (are there more recommendations linked to the risk) - $isRiskRelatedRecommendationFinal = \count($recommendationRiskTable->findByAnrAndOperationalInstanceRisk( - $recommendationRisk->getAnr(), - $recommendationRisk->getInstanceRiskOp() - )) === 1; - - // Automatically record the change in history before modifying values - $this->createRecoRiskOpHistoric($data, $recommendationRisk, $isRiskRelatedRecommendationFinal); - - if ($isRiskRelatedRecommendationFinal) { - // Overload observation for volatile comment (after measure) - $cacheCommentAfter = []; - - $riskRecoHistos = $this->recommendationHistoricTable->getEntityByFields([ - 'instanceRiskOp' => $recommendationRisk->getInstanceRiskOp()->getId() - ], ['id' => 'DESC']); - $c = 0; - - foreach ($riskRecoHistos as $riskRecoHisto) { - /* - On ne prend que: - - le dernier "final" - - et les précédent "non final" - */ - if (!$riskRecoHisto->get('final') || ($riskRecoHisto->get('final') && $c <= 0)) { - if (strlen($riskRecoHisto->get('cacheCommentAfter'))) { - $cacheCommentAfter[] = $riskRecoHisto->get('cacheCommentAfter'); - } - $c++; - } else { - break; - } - } - - /** @var InstanceRiskOp $instanceRiskOp */ - $instanceRiskOp = $recommendationRisk->getInstanceRiskOp(); - // array_reverse because "['id' => 'DESC']" - $instanceRiskOp->setComment(implode("\n\n", array_reverse($cacheCommentAfter))); - $instanceRiskOp->setMitigation(''); - $instanceRiskOp->setNetProb($instanceRiskOp->getTargetedProb()); - $instanceRiskOp->setCacheNetRisk($instanceRiskOp->getCacheTargetedRisk()); - foreach ($instanceRiskOp->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { - $operationalInstanceRiskScale->setNetValue($operationalInstanceRiskScale->getTargetedValue()); - $operationalInstanceRiskScale->setTargetedValue(-1); - } - - $instanceRiskOp->setTargetedProb(-1); - $instanceRiskOp->setCacheTargetedRisk(-1); - $instanceRiskOp->setKindOfMeasure(InstanceRiskOp::KIND_NOT_TREATED); - - $this->instanceRiskOpTable->saveEntity($instanceRiskOp); - } - } elseif ($recommendationRisk->getInstanceRisk() !== null) { // validate for information risks - // Verify if recommendation risk is final (are there more recommendations linked to the risk) - $isRiskRelatedRecommendationFinal = \count($recommendationRiskTable->findByAnrAndInstanceRisk( - $recommendationRisk->getAnr(), - $recommendationRisk->getInstanceRisk() - )) === 1; - - // Automatically record the change in history before modifying values - $this->createRecoRiskHistoric($data, $recommendationRisk, $isRiskRelatedRecommendationFinal); - - if ($isRiskRelatedRecommendationFinal) { - // Overload observation for volatile comment (after measure) - $cacheCommentAfter = []; - - $riskRecoHistos = $this->recommendationHistoricTable->getEntityByFields([ - 'instanceRisk' => $recommendationRisk->getInstanceRisk()->getId() - ], ['id' => 'DESC']); - $c = 0; - - foreach ($riskRecoHistos as $riskRecoHisto) { - /* - On ne prend que: - - le dernier "final" - - et les précédent "non final" - */ - if (!$riskRecoHisto->get('final') || ($riskRecoHisto->get('final') && $c <= 0)) { - if (strlen($riskRecoHisto->get('cacheCommentAfter'))) { - $cacheCommentAfter[] = $riskRecoHisto->get('cacheCommentAfter'); - } - $c++; - } else { - break; - } - } - - // Update instance risk - $instanceRisk = $recommendationRisk->getInstanceRisk(); - - $instanceRisk->setComment( - implode("\n\n", array_reverse($cacheCommentAfter)) - ); // array_reverse because "['id' => 'DESC']" - $instanceRisk->setCommentAfter(''); - - // Apply reduction vulnerability on risk - $oldVulRate = $instanceRisk->getVulnerabilityRate(); - $newVulnerabilityRate = $instanceRisk->getVulnerabilityRate() - $instanceRisk->getReductionAmount(); - $instanceRisk->setVulnerabilityRate($newVulnerabilityRate >= 0 ? $newVulnerabilityRate : 0); - - $instanceRisk->setRiskConfidentiality( - $this->getRiskC( - $instanceRisk->getInstance()->getConfidentiality(), - $instanceRisk->getThreatRate(), - $instanceRisk->getVulnerabilityRate() - ) - ); - $instanceRisk->setRiskIntegrity( - $this->getRiskI( - $instanceRisk->getInstance()->getIntegrity(), - $instanceRisk->getThreatRate(), - $instanceRisk->getVulnerabilityRate() - ) - ); - $instanceRisk->setRiskAvailability( - $this->getRiskD( - $instanceRisk->getInstance()->getAvailability(), - $instanceRisk->getThreatRate(), - $instanceRisk->getVulnerabilityRate() - ) - ); - - $risks = []; - $impacts = []; - if ($instanceRisk->getThreat()->getConfidentiality()) { - $risks[] = $instanceRisk->getRiskConfidentiality(); - $impacts[] = $instanceRisk->getInstance()->getConfidentiality(); - } - if ($instanceRisk->getThreat()->getIntegrity()) { - $risks[] = $instanceRisk->getRiskIntegrity(); - $impacts[] = $instanceRisk->getInstance()->getIntegrity(); - } - if ($instanceRisk->getThreat()->getAvailability()) { - $risks[] = $instanceRisk->getRiskAvailability(); - $impacts[] = $instanceRisk->getInstance()->getAvailability(); - } - - $instanceRisk->setCacheMaxRisk(\count($risks) ? max($risks) : -1); - $instanceRisk->setCacheTargetedRisk( - $this->getTargetRisk( - $impacts, - $instanceRisk->getThreatRate(), - $oldVulRate, - $instanceRisk->getReductionAmount() - ) - ); - - // Set reduction amount to 0 - $instanceRisk->setReductionAmount(0); - - // Change status to NOT_TREATED - $instanceRisk->setKindOfMeasure(InstanceRisk::KIND_NOT_TREATED); - - $this->instanceRiskTable->saveEntity($instanceRisk); - - // Impact on brothers - if ($recommendationRisk->hasGlobalObjectRelation()) { - $brothersInstances = $this->instanceTable->findByAnrAndObject( - $recommendationRisk->getAnr(), - $recommendationRisk->getGlobalObject() - ); - foreach ($brothersInstances as $brotherInstance) { - $brothersInstancesRisks = $this->instanceRiskTable->findByInstanceAndInstanceRiskRelations( - $brotherInstance, - $instanceRisk, - false, - true - ); - - foreach ($brothersInstancesRisks as $brotherInstanceRisk) { - $brotherInstanceRisk->setComment($instanceRisk->getComment()) - ->setCommentAfter($instanceRisk->getCommentAfter()) - ->setVulnerabilityRate($instanceRisk->getVulnerabilityRate()) - ->setRiskConfidentiality($instanceRisk->getRiskConfidentiality()) - ->setRiskIntegrity($instanceRisk->getRiskIntegrity()) - ->setRiskAvailability($instanceRisk->getRiskAvailability()) - ->setCacheMaxRisk($instanceRisk->getCacheMaxRisk()) - ->setCacheTargetedRisk($instanceRisk->getCacheTargetedRisk()) - ->setReductionAmount($instanceRisk->getReductionAmount()) - ->setKindOfMeasure($instanceRisk->getKindOfMeasure()); - - $this->instanceRiskTable->saveEntity($instanceRisk, false); - } - $this->instanceRiskTable->getDb()->flush(); - } - } - } - } - - $this->removeTheLink($recommendationRisk); - $this->updateRecommendationData($recommendationRisk->getRecommandation()); - } - - /** - * Creates an entry in the recommendation's history for information risks to keep a log of changes. - * - * @param array $data The history data (comment) - * @param RecommandationRisk $recoRisk The recommendation risk to historize - * @param bool $final Whether or not it's the final event - */ - public function createRecoRiskHistoric(array $data, RecommandationRisk $recoRisk, bool $final) - { - $reco = $recoRisk->getRecommandation(); - $instanceRisk = $recoRisk->getInstanceRisk(); - $anr = $recoRisk->getAnr(); - $lang = $anr->getLanguage(); - - $histo = [ - 'final' => $final, - 'implComment' => $data['comment'], - 'recoCode' => $reco->getCode(), - 'recoDescription' => $reco->getDescription(), - 'recoImportance' => $reco->getImportance(), - 'recoComment' => $reco->getComment(), - 'recoDuedate' => $reco->getDueDate(), - 'recoResponsable' => $reco->getResponsable(), - 'riskInstance' => $instanceRisk->getInstance()->{'getName' . $lang}(), - 'riskInstanceContext' => $instanceRisk->getInstance()->getHierarchyString(), - 'riskAsset' => $instanceRisk->getAsset()->getLabel($lang), - 'riskThreat' => $instanceRisk->getThreat()->getLabel($lang), - 'riskThreatVal' => $instanceRisk->getThreatRate(), - 'riskVul' => $instanceRisk->getVulnerability()->getLabel($lang), - 'riskVulValBefore' => $instanceRisk->getVulnerabilityRate(), - 'riskVulValAfter' => $final - ? max(0, $instanceRisk->getVulnerabilityRate() - $instanceRisk->getReductionAmount()) - : $instanceRisk->getVulnerabilityRate(), - 'riskKindOfMeasure' => $instanceRisk->getKindOfMeasure(), - 'riskCommentBefore' => $instanceRisk->getComment(), - 'riskCommentAfter' => $final ? $recoRisk->getCommentAfter() : $instanceRisk->getComment(), - 'riskMaxRiskBefore' => $instanceRisk->getCacheMaxRisk(), - 'riskMaxRiskAfter' => $final ? $instanceRisk->getCacheTargetedRisk() : $instanceRisk->getCacheMaxRisk(), - 'riskColorBefore' => $instanceRisk->getCacheMaxRisk() !== -1 - ? $this->anrService->getColor($anr, $instanceRisk->getCacheMaxRisk()) - : '', - 'cacheCommentAfter' => $recoRisk->getCommentAfter(), - 'riskColorAfter' => $final - ? ($instanceRisk->getCacheTargetedRisk() !== -1 - ? $this->anrService->getColor($anr, $instanceRisk->getCacheTargetedRisk()) - : '' - ) - : ($instanceRisk->getCacheMaxRisk() !== -1 - ? $this->anrService->getColor($anr, $instanceRisk->getCacheMaxRisk()) - : '' - ), - ]; - - $recoHisto = new RecommandationHistoric(); - $recoHisto->setLanguage($this->getLanguage()); - $recoHisto->setDbAdapter($this->recommendationHistoricTable->getDb()); - $recoHisto->exchangeArray($histo); - - $recoHisto->setAnr($anr); - $recoHisto->instanceRisk = $instanceRisk; - - $this->recommendationHistoricTable->save($recoHisto); - } - - /** - * Creates an entry in the recommendation's history for operational risks to keep a log of changes. - * - * @param array $data The history data (comment) - * @param RecommandationRisk $recoRisk The recommendation risk to historize - * @param bool $final Whether or not it's the final event - */ - public function createRecoRiskOpHistoric(array $data, RecommandationRisk $recoRisk, bool $final) - { - $recommendation = $recoRisk->getRecommandation(); - $instanceRiskOp = $recoRisk->getInstanceRiskOp(); - $anr = $recoRisk->getAnr(); - $lang = $anr->getLanguage(); - - $histo = [ - 'final' => $final, - 'implComment' => $data['comment'], - 'recoCode' => $recommendation->getCode(), - 'recoDescription' => $recommendation->getDescription(), - 'recoImportance' => $recommendation->getImportance(), - 'recoComment' => $recommendation->getComment(), - 'recoDuedate' => $recommendation->getDueDate(), - 'recoResponsable' => $recommendation->getResponsable(), - 'riskInstance' => $instanceRiskOp->getInstance()->{'getName' . $lang}(), - 'riskInstanceContext' => $instanceRiskOp->getInstance()->getHierarchyString(), - 'riskAsset' => $instanceRiskOp->getObject()->getAsset()->getLabel($lang), - 'riskOpDescription' => $instanceRiskOp->getRiskCacheLabel($lang), - 'netProbBefore' => $instanceRiskOp->getNetProb(), - 'riskKindOfMeasure' => $instanceRiskOp->getKindOfMeasure(), - 'riskCommentBefore' => $instanceRiskOp->getComment(), - 'riskCommentAfter' => $final ? $recoRisk->getCommentAfter() : $instanceRiskOp->getComment(), - 'riskMaxRiskBefore' => $instanceRiskOp->getCacheNetRisk(), - 'riskMaxRiskAfter' => $final ? $instanceRiskOp->getCacheTargetedRisk() : $instanceRiskOp->getCacheNetRisk(), - 'riskColorBefore' => $instanceRiskOp->getCacheNetRisk() !== -1 - ? $this->anrService->getColorRiskOp($anr, $instanceRiskOp->getCacheNetRisk()) - : '', - 'cacheCommentAfter' => $recoRisk->getCommentAfter(), - 'riskColorAfter' => $final - ? ($instanceRiskOp->getCacheTargetedRisk() !== -1 - ? $this->anrService->getColorRiskOp($anr, $instanceRiskOp->getCacheTargetedRisk()) - : '' - ) - : ($instanceRiskOp->getCacheNetRisk() !== -1 - ? $this->anrService->getColorRiskOp($anr, $instanceRiskOp->getCacheNetRisk()) - : '' - ), - - ]; - - $recoHisto = new RecommandationHistoric(); - $recoHisto->setLanguage($this->getLanguage()); - $recoHisto->setDbAdapter($this->recommendationHistoricTable->getDb()); - $recoHisto->exchangeArray($histo); - - $recoHisto->setAnr($anr); - $recoHisto->instanceRiskOp = $instanceRiskOp; - - $this->recommendationHistoricTable->save($recoHisto); - } - - /** - * Unlink the recommendation from related risk (remove the passed link between risks and recommendation). - */ - private function removeTheLink(RecommandationRisk $recommendationRisk): void - { - /** @var Table\RecommandationRiskTable $recommendationRiskTable */ - $recommendationRiskTable = $this->get('table'); - - if ($recommendationRisk->hasGlobalObjectRelation()) { - $recommendationsRisksLinkedByRecommendationGlobalObjectAndAmv = $recommendationRiskTable - ->findAllLinkedByRecommendationGlobalObjectAndAmv($recommendationRisk); - - foreach ($recommendationsRisksLinkedByRecommendationGlobalObjectAndAmv as $linkedRecommendationRisk) { - $recommendationRiskTable->deleteEntity($linkedRecommendationRisk, false); - } - $recommendationRiskTable->getDb()->flush(); - } else { - $recommendationRiskTable->deleteEntity($recommendationRisk); - } - } - - /** - * @throws OptimisticLockException - */ - private function updateRecommendationData(Recommandation $recommendation): void - { - $recommendation->incrementCounterTreated(); - - if (!$recommendation->hasLinkedRecommendationRisks()) { - $recommendation->setDueDate(null); - $recommendation->setResponsable(''); - $recommendation->setComment(''); - - $this->resetRecommendationsPositions( - $recommendation->getAnr(), - [$recommendation->getUuid() => $recommendation] - ); - } - - $this->recommendationTable->saveEntity($recommendation); - } -} diff --git a/src/Service/AnrRecommandationRiskServiceFactory.php b/src/Service/AnrRecommandationRiskServiceFactory.php deleted file mode 100755 index d188724f..00000000 --- a/src/Service/AnrRecommandationRiskServiceFactory.php +++ /dev/null @@ -1,30 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\RecommandationRisk', - 'table' => 'Monarc\FrontOffice\Model\Table\RecommandationRiskTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'recommendationTable' => 'Monarc\FrontOffice\Model\Table\RecommandationTable', - 'recommendationHistoricTable' => 'Monarc\FrontOffice\Model\Table\RecommendationHistoricTable', - 'instanceRiskTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskTable', - 'instanceRiskOpTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskOpTable', - 'anrService' => 'Monarc\FrontOffice\Service\AnrService', - 'instanceTable' => 'Monarc\FrontOffice\Model\Table\InstanceTable', - ]; -} diff --git a/src/Service/AnrRecommandationService.php b/src/Service/AnrRecommandationService.php deleted file mode 100755 index 755c96d5..00000000 --- a/src/Service/AnrRecommandationService.php +++ /dev/null @@ -1,288 +0,0 @@ -get('entity')->getFiltersForService(); - $recos = $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd, - $filterJoin, - $filterLeft - ); - - foreach ($recos as $key => $reco) { - $recos[$key]['timerColor'] = $this->getDueDateColor($reco['duedate']); - $recos[$key]['counterTreated'] = $reco['counterTreated'] === 0 - ? 'COMING' - : '_SMILE_IN_PROGRESS (' . $reco['counterTreated'] . ')'; - } - - return $recos; - } - - public function create($data, $last = true) - { - $anr = $this->anrTable->findById($data['anr']); - - $recommendationSet = $this->recommendationSetTable->findByAnrAndUuid($anr, $data['recommandationSet']); - - $entity = (new Recommandation()) - ->setAnr($anr) - ->setRecommandationSet($recommendationSet) - ->setImportance($data['importance']) - ->setCode($data['code']) - ->setDescription($data['description']) - ->setCreator($this->getConnectedUser()->getEmail()); - - $this->recommendationTable->saveEntity($entity, $last); - - return $entity->getUuid(); - } - - public function patch($id, $data) - { - $anr = $this->anrTable->findById($data['anr']); - - $recommendation = $this->recommendationTable->findByAnrAndUuid($anr, $id); - - if (!empty($data['duedate'])) { - try { - $recommendation->setDueDate(new DateTime($data['duedate'])); - } catch (Throwable $e) { - } - } elseif (isset($data['duedate']) && $data['duedate'] === '') { - $recommendation->setDueDate(null); - } - - if (!empty($data['recommandationSet']) - && $data['recommandationSet'] !== $recommendation->getRecommandationSet()->getUuid() - ) { - $recommendationSet = $this->recommendationSetTable->findByAnrAndUuid($anr, $data['recommandationSet']); - $recommendation->setRecommandationSet($recommendationSet); - } - - if (!empty($data['code']) && $data['code'] !== $recommendation->getCode()) { - $recommendation->setCode($data['code']); - } - if (!empty($data['description']) && $data['description'] !== $recommendation->getDescription()) { - $recommendation->setDescription($data['description']); - } - $isImportanceChanged = false; - if (!empty($data['importance']) && $recommendation->getImportance() !== $data['importance']) { - $isImportanceChanged = true; - $recommendation->setImportance($data['importance']); - } - if (isset($data['status']) && $recommendation->getStatus() !== (int)$data['status']) { - $recommendation->setStatus((int)$data['status']); - } - if (!empty($data['comment']) && $recommendation->getComment() !== $data['comment']) { - $recommendation->setComment($data['comment']); - } - if (!empty($data['responsable']) && $recommendation->getResponsable() !== $data['responsable']) { - $recommendation->setResponsable($data['responsable']); - } - if (!empty($data['position']) && $recommendation->getPosition() !== $data['position']) { - $recommendation->setPosition($data['position']); - } - - $this->recommendationTable->saveEntity($recommendation->setUpdater($this->getConnectedUser()->getEmail())); - - $this->updatePositions($recommendation, $data, $isImportanceChanged); - } - - public function update($id, $data) - { - foreach ($this->filterColumns as $filterColumn) { - unset($data[$filterColumn]); - } - - $this->patch($id, $data); - } - - /** - * @param array $id - * - * @return bool - * - * @throws EntityNotFoundException - * @throws OptimisticLockException - */ - public function delete($id) - { - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - $anr = $anrTable->findById($id['anr']); - $recommendation = $this->recommendationTable->findByAnrAndUuid($anr, $id['uuid']); - - if (!$recommendation->isPositionEmpty()) { - $this->resetRecommendationsPositions($anr, [$recommendation->getUuid() => $recommendation]); - } - - $this->recommendationTable->deleteEntity($recommendation); - - return true; - } - - /** - * Updates the position of the recommendation, based on the implicitPosition and/or previous field passed in $data. - */ - private function updatePositions(Recommandation $recommendation, array $data, bool $isImportanceChanged): void - { - if (!empty($data['implicitPosition'])) { - $newPosition = $recommendation->getPosition(); - - $linkedRecommendations = $this->recommendationTable - ->findLinkedWithRisksByAnrWithSpecifiedImportanceAndPositionAndExcludeRecommendations( - $recommendation->getAnr(), - [$recommendation->getUuid()], - ['r.position' => 'ASC'] - ); - - switch ($data['implicitPosition']) { - case AbstractEntity::IMP_POS_START: - foreach ($linkedRecommendations as $linkedRecommendation) { - if ($linkedRecommendation->isPositionHigherThan($recommendation->getPosition()) - && !$linkedRecommendation->isPositionLowerThan($recommendation->getPosition()) - ) { - $this->recommendationTable->saveEntity($linkedRecommendation->shiftPositionDown(), false); - } - } - - $newPosition = 1; - - break; - case AbstractEntity::IMP_POS_END: - $maxPosition = 1; - foreach ($linkedRecommendations as $linkedRecommendation) { - if ($linkedRecommendation->isPositionLowerThan($recommendation->getPosition())) { - $maxPosition = $linkedRecommendation->getPosition(); - $this->recommendationTable->saveEntity($linkedRecommendation->shiftPositionUp(), false); - } - } - - $newPosition = $maxPosition; - - break; - case AbstractEntity::IMP_POS_AFTER: - if (!empty($data['previous'])) { - $previousRecommendation = $this->recommendationTable->findByAnrAndUuid( - $recommendation->getAnr(), - $data['previous'] - ); - $isRecommendationMovedUp = $previousRecommendation->isPositionHigherThan( - $recommendation->getPosition() - ); - $newPosition = $isRecommendationMovedUp ? $previousRecommendation->getPosition() + 1 - : $previousRecommendation->getPosition(); - - foreach ($linkedRecommendations as $linkedRecommendation) { - if ($isRecommendationMovedUp - && $linkedRecommendation->isPositionLowerThan($previousRecommendation->getPosition()) - && $linkedRecommendation->isPositionHigherThan($recommendation->getPosition()) - ) { - $this->recommendationTable->saveEntity( - $linkedRecommendation->shiftPositionDown(), - false - ); - } elseif (!$isRecommendationMovedUp - && $linkedRecommendation->isPositionLowerThan($recommendation->getPosition()) - && $linkedRecommendation->isPositionHigherOrEqualThan( - $previousRecommendation->getPosition() - ) - ) { - $this->recommendationTable->saveEntity($linkedRecommendation->shiftPositionUp(), false); - } - } - } - break; - } - - $this->recommendationTable->saveEntity($recommendation->setPosition($newPosition)); - } elseif ($isImportanceChanged && !$recommendation->getRecommendationRisks()->isEmpty()) { - foreach ($recommendation->getRecommendationRisks() as $recommendationRisk) { - $linkedRisk = $recommendationRisk->getInstanceRisk() ?? $recommendationRisk->getInstanceRiskOp(); - $this->updateInstanceRiskRecommendationsPositions($linkedRisk); - - break; - } - } - } - - /** - * Computes the due date color for the recommendation. Returns 'no-date' if no due date is set on the - * recommendation, 'large' if there's a lot of time remaining, 'warning' if there is less than 15 days remaining, - * and 'alert' if the due date is in the past. - * @param string $dueDate The due date, in yyyy-mm-dd format - * @return string 'no-date', 'large', 'warning', 'alert' - */ - protected function getDueDateColor($dueDate) - { - if (empty($dueDate) || $dueDate == '0000-00-00') { - return 'no-date'; - } else { - $now = time(); - if ($dueDate instanceof DateTime) { - $dueDate = $dueDate->getTimestamp(); - } else { - $dueDate = strtotime($dueDate); - } - $diff = $dueDate - $now; - - if ($diff < 0) { - return "alert"; - } else { - $days = round($diff / 60 / 60 / 24); - if ($days <= 15) {//arbitrary 15 days - return "warning"; - } else { - return "large"; - } - } - } - } -} diff --git a/src/Service/AnrRecommandationServiceFactory.php b/src/Service/AnrRecommandationServiceFactory.php deleted file mode 100755 index ab3fd7eb..00000000 --- a/src/Service/AnrRecommandationServiceFactory.php +++ /dev/null @@ -1,28 +0,0 @@ - Recommandation::class, - 'table' => Table\RecommandationTable::class, - 'anrTable' => Table\AnrTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'recommendationTable' => Table\RecommandationTable::class, - 'recommendationSetTable' => Table\RecommandationSetTable::class, - ]; -} diff --git a/src/Service/AnrRecommandationSetService.php b/src/Service/AnrRecommandationSetService.php deleted file mode 100644 index 8c2cde2b..00000000 --- a/src/Service/AnrRecommandationSetService.php +++ /dev/null @@ -1,87 +0,0 @@ -get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - 1, - 0, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd - ); - - return $data; - } - - /** - * @param array $id - * - * @return bool - * - * @throws EntityNotFoundException - * @throws OptimisticLockException - */ - public function delete($id) - { - /** @var RecommandationSetTable $recommendationSetTable */ - $recommendationSetTable = $this->get('table'); - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - $anr = $anrTable->findById($id['anr']); - $recommendationSet = $recommendationSetTable->findByAnrAndUuid($anr, $id['uuid']); - - $recommendationsToResetPositions = []; - foreach ($recommendationSet->getRecommandations() as $recommendation) { - if (!$recommendation->isPositionEmpty()) { - $recommendationsToResetPositions[$recommendation->getUuid()] = $recommendation; - } - } - if (!empty($recommendationsToResetPositions)) { - $this->resetRecommendationsPositions($anr, $recommendationsToResetPositions); - } - - $recommendationSetTable->deleteEntity($recommendationSet); - - return true; - } -} diff --git a/src/Service/AnrRecommandationSetServiceFactory.php b/src/Service/AnrRecommandationSetServiceFactory.php deleted file mode 100644 index 67997bd4..00000000 --- a/src/Service/AnrRecommandationSetServiceFactory.php +++ /dev/null @@ -1,29 +0,0 @@ - Table\RecommandationSetTable::class, - 'entity' => RecommandationSet::class, - 'anrTable' => Table\AnrTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'recommendationTable' => Table\RecommandationTable::class, - ]; -} diff --git a/src/Service/AnrRecommendationHistoryService.php b/src/Service/AnrRecommendationHistoryService.php new file mode 100755 index 00000000..2b784d11 --- /dev/null +++ b/src/Service/AnrRecommendationHistoryService.php @@ -0,0 +1,193 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(Anr $anr): array + { + $recommendationsHistoryList = []; + /** @var RecommendationHistory $recommendationHistory */ + foreach ($this->recommendationHistoryTable->findByAnr($anr) as $recommendationHistory) { + $recommendationsHistoryList[] = [ + 'id' => $recommendationHistory->getId(), + 'cacheCommentAfter' => $recommendationHistory->getCacheCommentAfter(), + 'implComment' => $recommendationHistory->getImplComment(), + 'final' => (int)$recommendationHistory->isFinal(), + 'creator' => $recommendationHistory->getCreator(), + 'createdAt' => [ + 'date' => $recommendationHistory->getCreatedAt() !== null + ? $recommendationHistory->getCreatedAt()->format('Y-m-d H:i:s') + : '', + ], + 'recoCode' => $recommendationHistory->getRecoCode(), + 'recoDescription' => $recommendationHistory->getRecoDescription(), + 'recoComment' => $recommendationHistory->getRecoComment(), + 'recoImportance' => $recommendationHistory->getRecoImportance(), + 'recoDuedate' => [ + 'date' => $recommendationHistory->getRecoDueDate() !== null + ? $recommendationHistory->getRecoDueDate()->format('Y-m-d H:i:s') + : '', + ], + 'recoResponsable' => $recommendationHistory->getRecoResponsable(), + 'riskAsset' => $recommendationHistory->getRiskAsset(), + 'riskInstance' => $recommendationHistory->getRiskInstance(), + 'riskInstanceContext' => $recommendationHistory->getRiskInstanceContext(), + 'riskThreat' => $recommendationHistory->getRiskThreat(), + 'riskVul' => $recommendationHistory->getRiskVul(), + 'riskOpDescription' => $recommendationHistory->getRiskOpDescription(), + 'riskKindOfMeasure' => $recommendationHistory->getRiskKindOfMeasure(), + 'riskColorBefore' => $recommendationHistory->getRiskColorBefore(), + 'riskColorAfter' => $recommendationHistory->getRiskColorAfter(), + 'riskCommentBefore' => $recommendationHistory->getRiskCommentBefore(), + 'riskCommentAfter' => $recommendationHistory->getRiskCommentAfter(), + 'riskMaxRiskBefore' => $recommendationHistory->getRiskMaxRiskBefore(), + 'riskMaxRiskAfter' => $recommendationHistory->getRiskMaxRiskAfter(), + 'instanceRisk' => $recommendationHistory->getInstanceRisk() !== null, + 'instanceRiskOp' => $recommendationHistory->getInstanceRiskOp() !== null, + ]; + } + + return $recommendationsHistoryList; + } + + public function createFromRecommendationRisk( + array $data, + RecommendationRisk $recommendationRisk, + bool $isFinal, + bool $saveInDb = true + ): RecommendationHistory { + $recommendation = $recommendationRisk->getRecommendation(); + $anr = $recommendation->getAnr(); + $languageIndex = $anr->getLanguage(); + + $recommendationHistory = (new RecommendationHistory()) + ->setAnr($anr) + ->setImplComment($data['comment']) + ->setIsFinal($isFinal) + ->setRecoCode($recommendation->getCode()) + ->setRecoDescription($recommendation->getDescription()) + ->setRecoImportance($recommendation->getImportance()) + ->setRecoComment($recommendation->getComment()) + ->setRecoDueDate($recommendation->getDueDate()) + ->setRecoResponsable($recommendation->getResponsible()) + ->setRiskInstance($recommendationRisk->getInstance()->getName($languageIndex)) + ->setRiskInstanceContext($recommendationRisk->getInstance()->getHierarchyString()) + ->setCacheCommentAfter($recommendationRisk->getCommentAfter()) + ->setCreator($this->connectedUser->getFirstname() . ' ' . $this->connectedUser->getLastname()); + + $instanceRisk = $recommendationRisk->getInstanceRisk(); + $instanceRiskOp = $recommendationRisk->getInstanceRiskOp(); + if ($instanceRisk !== null) { + if ($isFinal) { + $riskColorAfter = $instanceRisk->getCacheTargetedRisk() !== -1 + ? $anr->getInformationalRiskLevelColor($instanceRisk->getCacheTargetedRisk()) + : ''; + } else { + $riskColorAfter = $instanceRisk->getCacheMaxRisk() !== -1 + ? $anr->getInformationalRiskLevelColor($instanceRisk->getCacheMaxRisk()) + : ''; + } + $recommendationHistory->setInstanceRisk($instanceRisk) + ->setRiskAsset($instanceRisk->getAsset()->getLabel($languageIndex)) + ->setRiskThreat($instanceRisk->getThreat()->getLabel($languageIndex)) + ->setRiskThreatVal($instanceRisk->getThreatRate()) + ->setRiskVul($instanceRisk->getVulnerability()->getLabel($languageIndex)) + ->setRiskVulValBefore($instanceRisk->getVulnerabilityRate()) + ->setRiskVulValAfter( + $isFinal + ? max(0, $instanceRisk->getVulnerabilityRate() - $instanceRisk->getReductionAmount()) + : $instanceRisk->getVulnerabilityRate() + ) + ->setRiskKindOfMeasure($instanceRisk->getKindOfMeasure()) + ->setRiskCommentBefore($instanceRisk->getComment()) + ->setRiskCommentAfter($isFinal ? $recommendationRisk->getCommentAfter() : $instanceRisk->getComment()) + ->setRiskMaxRiskBefore($instanceRisk->getCacheMaxRisk()) + ->setRiskMaxRiskAfter( + $isFinal ? $instanceRisk->getCacheTargetedRisk() : $instanceRisk->getCacheMaxRisk() + )->setRiskColorBefore( + $instanceRisk->getCacheMaxRisk() !== -1 + ? $recommendation->getAnr()->getInformationalRiskLevelColor($instanceRisk->getCacheMaxRisk()) + : '' + )->setRiskColorAfter($riskColorAfter); + } elseif ($instanceRiskOp !== null) { + if ($isFinal) { + $riskColorAfter = $instanceRiskOp->getCacheTargetedRisk() !== -1 + ? $anr->getOperationalRiskLevelColor($instanceRiskOp->getCacheTargetedRisk()) + : ''; + } else { + $riskColorAfter = $instanceRiskOp->getCacheNetRisk() !== -1 + ? $anr->getOperationalRiskLevelColor($instanceRiskOp->getCacheNetRisk()) + : ''; + } + $recommendationHistory->setInstanceRiskOp($instanceRiskOp) + ->setRiskAsset($instanceRiskOp->getObject()->getAsset()->getLabel($languageIndex)) + ->setRiskOpDescription($instanceRiskOp->getRiskCacheLabel($languageIndex)) + ->setNetProbBefore($instanceRiskOp->getNetProb()) + ->setRiskKindOfMeasure($instanceRiskOp->getKindOfMeasure()) + ->setRiskCommentBefore($instanceRiskOp->getComment()) + ->setRiskCommentAfter($isFinal ? $recommendationRisk->getCommentAfter() : $instanceRiskOp->getComment()) + ->setRiskMaxRiskBefore($instanceRiskOp->getCacheNetRisk()) + ->setRiskMaxRiskAfter( + $isFinal ? $instanceRiskOp->getCacheTargetedRisk() : $instanceRiskOp->getCacheNetRisk() + )->setRiskColorBefore( + $instanceRiskOp->getCacheNetRisk() !== -1 + ? $anr->getOperationalRiskLevelColor($instanceRiskOp->getCacheNetRisk()) + : '' + )->setRiskColorAfter($riskColorAfter); + } + + $this->recommendationHistoryTable->save($recommendationHistory, $saveInDb); + + return $recommendationHistory; + } + + public function getValidatedCachedCommentsList( + InstanceRisk|InstanceRiskOp $instanceRisk, + RecommendationHistory $currentRecommendationHistory + ): array { + $recommendationsHistory = $this->recommendationHistoryTable->findByInstanceRiskOrderBy( + $instanceRisk, + ['id' => Criteria::DESC] + ); + + $cacheCommentsAfter = $currentRecommendationHistory->getCacheCommentAfter() !== null + ? [$currentRecommendationHistory->getCacheCommentAfter()] + : []; + foreach ($recommendationsHistory as $recommendationHistory) { + /* Get other validated recommendations comments linked to the same risk before the final one. */ + if ($recommendationHistory->isFinal()) { + break; + } + if ($recommendationHistory->getCacheCommentAfter() !== '') { + $cacheCommentsAfter[] = $recommendationHistory->getCacheCommentAfter(); + } + } + + return $cacheCommentsAfter; + } +} diff --git a/src/Service/AnrRecommendationRiskService.php b/src/Service/AnrRecommendationRiskService.php new file mode 100755 index 00000000..b2b204ab --- /dev/null +++ b/src/Service/AnrRecommendationRiskService.php @@ -0,0 +1,583 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $formattedInputParams): array + { + $includeRelations = $formattedInputParams->hasFilterFor('recommendation.uuid') + || $formattedInputParams->hasFilterFor('includeRelations'); + $recommendationRisksData = []; + $globalObjectsUuids = []; + /** @var Entity\RecommendationRisk $recommendationRisk */ + foreach ($this->recommendationRiskTable->findByParams($formattedInputParams) as $recommendationRisk) { + if ($includeRelations + && $recommendationRisk->getGlobalObject() !== null + && isset($globalObjectsUuids[$recommendationRisk->getGlobalObject()->getUuid()]) + ) { + continue; + } + + $recommendationRisksData[] = $this->getPreparedRecommendationRiskData( + $recommendationRisk, + $includeRelations + ); + + if ($includeRelations && $recommendationRisk->getGlobalObject() !== null) { + $globalObjectsUuids[$recommendationRisk->getGlobalObject()->getUuid()] = true; + } + } + + return $recommendationRisksData; + } + + public function getCount(FormattedInputParams $formattedInputParams): int + { + return $this->recommendationRiskTable->countByParams($formattedInputParams); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\RecommendationRisk + { + /** @var Entity\Recommendation $recommendation */ + $recommendation = $this->recommendationTable->findByUuidAndAnr($data['recommendation'], $anr); + /** @var Entity\InstanceRiskOp|Entity\InstanceRisk $instanceRisk */ + $instanceRisk = !empty($data['instanceRiskOp']) + ? $this->instanceRiskOpTable->findByIdAndAnr($data['instanceRiskOp'], $anr) + : $this->instanceRiskTable->findByIdAndAnr($data['instanceRisk'], $anr); + + /* Verify existence. */ + if (($instanceRisk instanceof Entity\InstanceRisk && $this->recommendationRiskTable + ->existsWithAnrRecommendationAndInstanceRisk($anr, $recommendation, $instanceRisk) + ) + || ($instanceRisk instanceof Entity\InstanceRiskOp && $this->recommendationRiskTable + ->existsWithAnrRecommendationAndInstanceRiskOp($anr, $recommendation, $instanceRisk) + ) + ) { + throw new Exception('The risk is already linked to this recommendation', 412); + } + + $recommendationRisk = $this->createRecommendationRisk($recommendation, $instanceRisk, '', $saveInDb); + + if ($instanceRisk instanceof Entity\InstanceRisk + && $instanceRisk->getAmv() + && $instanceRisk->getInstance()->getObject()->isScopeGlobal() + ) { + /* Link recommendation for the other global instances, where AMVs are matched */ + $siblingInstances = $this->instanceTable->findGlobalSiblingsByAnrAndInstance( + $anr, + $instanceRisk->getInstance() + ); + foreach ($siblingInstances as $siblingInstance) { + foreach ($siblingInstance->getInstanceRisks() as $siblingInstanceRisk) { + if ($siblingInstanceRisk->getAmv() + && $siblingInstanceRisk->getAmv()->getUuid() === $instanceRisk->getAmv()->getUuid() + ) { + $this->createRecommendationRisk($recommendation, $siblingInstanceRisk, '', $saveInDb); + } + } + } + } + + $this->updateInstanceRiskRecommendationsPositions($instanceRisk); + + return $recommendationRisk; + } + + public function patch(Entity\Anr $anr, int $id, array $data): Entity\RecommendationRisk + { + /** @var Entity\RecommendationRisk $recommendationRisk */ + $recommendationRisk = $this->recommendationRiskTable->findByIdAndAnr($id, $anr); + + if ($data['commentAfter'] !== $recommendationRisk->getCommentAfter()) { + $recommendationRisk->setCommentAfter($data['commentAfter']) + ->setUpdater($this->connectedUser->getEmail()); + + $this->recommendationRiskTable->save($recommendationRisk); + } + + return $recommendationRisk; + } + + public function delete(Entity\Anr $anr, int $id): void + { + /** @var Entity\RecommendationRisk $recommendationRisk */ + $recommendationRisk = $this->recommendationRiskTable->findByIdAndAnr($id, $anr); + + $recommendation = $recommendationRisk->getRecommendation(); + $instanceRisk = $recommendationRisk->getInstanceRisk(); + if ($instanceRisk !== null + && $instanceRisk->getAmv() !== null + && $recommendationRisk->hasGlobalObjectRelation() + ) { + /* Removing all the other instance risks, except of current linked to the global object, retrieved by AMV */ + /** @var Entity\Amv $amv */ + $amv = $instanceRisk->getAmv(); + $siblingInstanceRisks = $this->instanceRiskTable->findByAmv($amv); + $siblingInstanceRisksIds = []; + foreach ($siblingInstanceRisks as $siblingInstanceRisk) { + if ($instanceRisk->getInstance()->getObject()->isEqualTo( + $siblingInstanceRisk->getInstance()->getObject() + )) { + $siblingInstanceRisksIds[] = $siblingInstanceRisk->getId(); + } + } + + foreach ($recommendation->getRecommendationRisks() as $otherRecommendationRisk) { + if ($otherRecommendationRisk->getInstanceRisk() !== null + && $otherRecommendationRisk->getId() !== $recommendationRisk->getId() + && \in_array($otherRecommendationRisk->getInstanceRisk()->getId(), $siblingInstanceRisksIds, true) + ) { + $this->recommendationRiskTable->remove($otherRecommendationRisk); + } + } + } + + $this->recommendationRiskTable->remove($recommendationRisk); + + // Reset the recommendation's position if it's not linked to other risks anymore. + if (!$recommendation->hasLinkedRecommendationRisks()) { + $this->resetRecommendationsPositions( + $recommendation->getAnr(), + [$recommendation->getUuid() => $recommendation] + ); + } + } + + public function getTreatmentPlan(Entity\Anr $anr): array + { + $linkedRecommendations = $this->recommendationTable + ->findLinkedWithRisksByAnrWithSpecifiedImportanceAndPositionAndExcludeRecommendations( + $anr, + [], + ['r.position' => 'ASC'] + ); + + $treatmentPlan = []; + foreach ($linkedRecommendations as $linkedRecommendation) { + $instanceRisksData = []; + $globalObjects = []; + foreach ($linkedRecommendation->getRecommendationRisks() as $index => $recommendationRisk) { + $instanceRisk = $recommendationRisk->getInstanceRisk(); + if ($instanceRisk === null) { + $instanceRisk = $recommendationRisk->getInstanceRiskOp(); + $type = 'risksop'; + $instanceRiskData = [ + 'id' => $instanceRisk->getId(), + 'cacheNetRisk' => $instanceRisk->getCacheNetRisk(), + 'cacheTargetedRisk' => $instanceRisk->getCacheTargetedRisk(), + 'comment' => $instanceRisk->getComment(), + ]; + } else { + $type = 'risks'; + $instanceRiskData = [ + 'id' => $instanceRisk->getId(), + 'cacheMaxRisk' => $instanceRisk->getCacheMaxRisk(), + 'cacheTargetedRisk' => $instanceRisk->getCacheTargetedRisk(), + 'comment' => $instanceRisk->getComment(), + ]; + } + + if ($type === 'risks' && $recommendationRisk->hasGlobalObjectRelation()) { + $path = $recommendationRisk->getInstance()->getName($anr->getLanguage()); + $globalObjectUuid = $recommendationRisk->getGlobalObject()->getUuid(); + $assetUuid = $recommendationRisk->getAsset()->getUuid(); + $threatUuid = $recommendationRisk->getThreat()->getUuid(); + $vulnerabilityUuid = $recommendationRisk->getVulnerability()->getUuid(); + $globalObject = $globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid] + ?? null; + if ($globalObject !== null) { + if ($globalObject['maxRisk'] < $instanceRisk->getCacheMaxRisk()) { + $globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid]['maxRisk'] + = $instanceRisk->getCacheMaxRisk(); + $instanceRisksData[$type][$globalObject['index']] = array_merge($instanceRiskData, [ + 'path' => $path, + 'isGlobal' => true, + ]); + } + + continue; + } + + $globalObjects[$globalObjectUuid][$assetUuid][$threatUuid][$vulnerabilityUuid] = [ + 'index' => $index, + 'maxRisk' => $instanceRisk->getCacheMaxRisk(), + ]; + } else { + $path = $instanceRisk->getInstance()->getHierarchyString(); + } + + $instanceRisksData[$type][$index] = array_merge($instanceRiskData, [ + 'path' => $path, + 'isGlobal' => $recommendationRisk->hasGlobalObjectRelation(), + ]); + } + + $treatmentPlan[] = array_merge([ + 'uuid' => $linkedRecommendation->getUuid(), + 'code' => $linkedRecommendation->getCode(), + 'description' => $linkedRecommendation->getDescription(), + 'importance' => $linkedRecommendation->getImportance(), + 'position' => $linkedRecommendation->getPosition(), + 'comment' => $linkedRecommendation->getComment(), + 'status' => $linkedRecommendation->getStatus(), + 'responsable' => $linkedRecommendation->getResponsible(), + 'duedate' => $linkedRecommendation->getDueDate() !== null + ? $linkedRecommendation->getDueDate()->format('Y-m-d') + : '', + 'counterTreated' => $linkedRecommendation->getCounterTreated(), + ], $instanceRisksData); + } + + return $treatmentPlan; + } + + public function createRecommendationRisk( + Entity\Recommendation $recommendation, + Entity\InstanceRisk|Entity\InstanceRiskOp $instanceRisk, + string $commentAfter = '', + bool $saveInDb = true + ): Entity\RecommendationRisk { + /** @var Entity\Instance $instance */ + $instance = $instanceRisk->getInstance(); + $recommendationRisk = (new Entity\RecommendationRisk()) + ->setAnr($recommendation->getAnr()) + ->setRecommendation($recommendation) + ->setInstance($instance) + ->setCommentAfter($commentAfter) + ->setCreator($this->connectedUser->getEmail()); + if ($instanceRisk instanceof Entity\InstanceRiskOp) { + $recommendationRisk->setInstanceRiskOp($instanceRisk); + } else { + $recommendationRisk->setInstanceRisk($instanceRisk) + ->setAsset($instanceRisk->getAsset()) + ->setThreat($instanceRisk->getThreat()) + ->setVulnerability($instanceRisk->getVulnerability()); + } + + if ($instance->getObject()->isScopeGlobal()) { + /** @var Entity\MonarcObject $object */ + $object = $instance->getObject(); + $recommendationRisk->setGlobalObject($object); + } + + $this->recommendationRiskTable->save($recommendationRisk, $saveInDb); + + return $recommendationRisk; + } + + public function resetRecommendationsPositionsToDefault(Entity\Anr $anr): void + { + $recommendationRisks = $this->recommendationRiskTable->findByAnrOrderByAndCanExcludeNotTreated( + $anr, + ['r.importance' => 'DESC', 'r.code' => 'ASC'] + ); + + $position = 1; + $updatedRecommendationsUuid = []; + foreach ($recommendationRisks as $recommendationRisk) { + $recommendation = $recommendationRisk->getRecommendation(); + if (!isset($updatedRecommendationsUuid[$recommendation->getUuid()])) { + $this->recommendationTable->save( + $recommendation->setPosition($position++)->setUpdater($this->connectedUser->getEmail()), + false + ); + $updatedRecommendationsUuid[$recommendation->getUuid()] = true; + } + } + $this->recommendationTable->flush(); + } + + /** + * Validates a recommendation risk. + */ + public function validateFor(Entity\Anr $anr, int $recommendationRiskId, array $data): void + { + /** @var Entity\RecommendationRisk $recommendationRisk */ + $recommendationRisk = $this->recommendationRiskTable->findByIdAndAnr($recommendationRiskId, $anr); + + if ($recommendationRisk->getInstanceRiskOp() !== null) { + /** @var Entity\InstanceRiskOp $instanceRiskOp */ + $instanceRiskOp = $recommendationRisk->getInstanceRiskOp(); + + /* Verify if recommendation risk is final (are there more recommendations linked to the risk) */ + $isFinalValidation = $instanceRiskOp->getRecommendationRisks()->count() === 1; + + /* Tracks the change in history before modifying values. */ + $recommendationHistory = $this->recommendationHistoryService->createFromRecommendationRisk( + $data, + $recommendationRisk, + $isFinalValidation, + false + ); + + if ($isFinalValidation) { + /* Obtain list of new controls (commentAfter), that were specified since the new validation process + is started of all the recommendations linked to the risk. */ + $cacheCommentsAfter = $this->recommendationHistoryService->getValidatedCachedCommentsList( + $instanceRiskOp, + $recommendationHistory + ); + + /* array_reverse because "['id' => 'DESC']" */ + $instanceRiskOp->setComment(implode("\n\n", array_reverse($cacheCommentsAfter))) + ->setMitigation('') + ->setNetProb($instanceRiskOp->getTargetedProb()) + ->setCacheNetRisk($instanceRiskOp->getCacheTargetedRisk()) + ->setTargetedProb(-1) + ->setCacheTargetedRisk(-1) + ->setKindOfMeasure(InstanceRiskOpSuperClass::KIND_NOT_TREATED); + foreach ($instanceRiskOp->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { + $operationalInstanceRiskScale->setNetValue($operationalInstanceRiskScale->getTargetedValue()); + $operationalInstanceRiskScale->setTargetedValue(-1); + } + + $this->instanceRiskOpTable->save($instanceRiskOp, false); + } + } elseif ($recommendationRisk->getInstanceRisk() !== null) { + /** @var Entity\InstanceRisk $instanceRisk */ + $instanceRisk = $recommendationRisk->getInstanceRisk(); + + /* Verify if recommendation risk is final (are there more recommendations linked to the risk) */ + $isFinalValidation = $instanceRisk->getRecommendationRisks()->count() === 1; + + /* Tracks the change in history before modifying values. */ + $recommendationHistory = $this->recommendationHistoryService->createFromRecommendationRisk( + $data, + $recommendationRisk, + $isFinalValidation, + false + ); + + if ($isFinalValidation) { + /* Obtain list of new controls (commentAfter), that were specified since the new validation process + is started of all the recommendations linked to the risk. */ + $cacheCommentsAfter = $this->recommendationHistoryService->getValidatedCachedCommentsList( + $instanceRisk, + $recommendationHistory + ); + + /* Apply reduction vulnerability on risk. */ + $oldVulRate = $instanceRisk->getVulnerabilityRate(); + $newVulnerabilityRate = $instanceRisk->getVulnerabilityRate() - $instanceRisk->getReductionAmount(); + /* array_reverse because "['id' => 'DESC']" */ + $instanceRisk + ->setComment(implode("\n\n", array_reverse($cacheCommentsAfter))) + ->setCommentAfter('') + ->setVulnerabilityRate($newVulnerabilityRate >= 0 ? $newVulnerabilityRate : 0) + ->setRiskConfidentiality($this->calculateRiskConfidentiality( + $instanceRisk->getInstance()->getConfidentiality(), + $instanceRisk->getThreatRate(), + $instanceRisk->getVulnerabilityRate() + ))->setRiskIntegrity($this->calculateRiskIntegrity( + $instanceRisk->getInstance()->getIntegrity(), + $instanceRisk->getThreatRate(), + $instanceRisk->getVulnerabilityRate() + ))->setRiskAvailability($this->calculateRiskAvailability( + $instanceRisk->getInstance()->getAvailability(), + $instanceRisk->getThreatRate(), + $instanceRisk->getVulnerabilityRate() + )); + + $risks = []; + $impacts = []; + if ($instanceRisk->getThreat()->getConfidentiality()) { + $risks[] = $instanceRisk->getRiskConfidentiality(); + $impacts[] = $instanceRisk->getInstance()->getConfidentiality(); + } + if ($instanceRisk->getThreat()->getIntegrity()) { + $risks[] = $instanceRisk->getRiskIntegrity(); + $impacts[] = $instanceRisk->getInstance()->getIntegrity(); + } + if ($instanceRisk->getThreat()->getAvailability()) { + $risks[] = $instanceRisk->getRiskAvailability(); + $impacts[] = $instanceRisk->getInstance()->getAvailability(); + } + + $instanceRisk->setCacheMaxRisk(\count($risks) ? max($risks) : -1) + ->setCacheTargetedRisk($this->calculateTargetRisk( + $impacts, + $instanceRisk->getThreatRate(), + $oldVulRate, + $instanceRisk->getReductionAmount() + )) + ->setReductionAmount(0) + ->setKindOfMeasure(InstanceRiskSuperClass::KIND_NOT_TREATED); + + $this->instanceRiskTable->save($instanceRisk, false); + + // Impact on brothers + if ($recommendationRisk->hasGlobalObjectRelation()) { + $brothersInstances = $this->instanceTable->findByAnrAndObject( + $recommendationRisk->getAnr(), + $recommendationRisk->getGlobalObject() + ); + foreach ($brothersInstances as $brotherInstance) { + $brothersInstancesRisks = $this->instanceRiskTable->findByInstanceAndInstanceRiskRelations( + $brotherInstance, + $instanceRisk, + false, + true + ); + + foreach ($brothersInstancesRisks as $brotherInstanceRisk) { + $brotherInstanceRisk->setComment($instanceRisk->getComment()) + ->setCommentAfter($instanceRisk->getCommentAfter()) + ->setVulnerabilityRate($instanceRisk->getVulnerabilityRate()) + ->setRiskConfidentiality($instanceRisk->getRiskConfidentiality()) + ->setRiskIntegrity($instanceRisk->getRiskIntegrity()) + ->setRiskAvailability($instanceRisk->getRiskAvailability()) + ->setCacheMaxRisk($instanceRisk->getCacheMaxRisk()) + ->setCacheTargetedRisk($instanceRisk->getCacheTargetedRisk()) + ->setReductionAmount($instanceRisk->getReductionAmount()) + ->setKindOfMeasure($instanceRisk->getKindOfMeasure()); + + $this->instanceRiskTable->save($brotherInstanceRisk, false); + } + } + } + } + } + + $this->removeTheLink($recommendationRisk); + $this->validateRecommendation($recommendationRisk->getRecommendation()); + } + + /** + * Unlink the recommendation from related risk (remove the passed link between risks and recommendation). + */ + private function removeTheLink(Entity\RecommendationRisk $recommendationRisk): void + { + if ($recommendationRisk->hasGlobalObjectRelation()) { + $recommendationsRisksLinkedByRecommendationGlobalObjectAndAmv = $this->recommendationRiskTable + ->findAllLinkedByRecommendationGlobalObjectAndAmv($recommendationRisk); + + foreach ($recommendationsRisksLinkedByRecommendationGlobalObjectAndAmv as $linkedRecommendationRisk) { + $this->recommendationRiskTable->remove($linkedRecommendationRisk, false); + } + $this->recommendationRiskTable->flush(); + } else { + $this->recommendationRiskTable->remove($recommendationRisk); + } + } + + private function validateRecommendation(Entity\Recommendation $recommendation): void + { + $recommendation->incrementCounterTreated(); + + if (!$recommendation->hasLinkedRecommendationRisks()) { + $recommendation->setDueDate(null) + ->setResponsible('') + ->setComment(''); + + $this->resetRecommendationsPositions( + $recommendation->getAnr(), + [$recommendation->getUuid() => $recommendation] + ); + } + + $this->recommendationTable->save($recommendation); + } + + private function getPreparedRecommendationRiskData( + Entity\RecommendationRisk $recommendationRisk, + bool $extendedFormat = true + ): array { + $recommendation = $recommendationRisk->getRecommendation(); + $recommendationRiskData = [ + 'id' => $recommendationRisk->getId(), + 'recommendation' => [ + 'uuid' => $recommendation->getUuid(), + 'code' => $recommendation->getCode(), + 'description' => $recommendation->getDescription(), + 'importance' => $recommendation->getImportance(), + 'position' => $recommendation->getPosition(), + 'recommendationSet' => [ + 'uuid' => $recommendation->getRecommendationSet()->getUuid(), + 'label' => $recommendation->getRecommendationSet()->getLabel(), + ], + ], + 'commentAfter' => $recommendationRisk->getCommentAfter(), + ]; + if ($extendedFormat) { + $instance = $recommendationRisk->getInstance(); + $recommendationRiskData['instance'] = array_merge([ + 'id' => $instance->getId(), + 'object' => [ + 'uuid' => $instance->getObject()->getUuid(), + ], + ], $instance->getNames()); + $recommendationRiskData['asset'] = array_merge([ + 'uuid' => $instance->getAsset()->getUuid(), + 'type' => $instance->getAsset()->getType(), + ], $instance->getAsset()->getLabels()); + if ($recommendationRisk->getThreat() !== null && $recommendationRisk->getVulnerability() !== null) { + $recommendationRiskData['threat'] = array_merge([ + 'uuid' => $recommendationRisk->getThreat()->getUuid(), + 'code' => $recommendationRisk->getThreat()->getCode(), + ], $recommendationRisk->getThreat()->getLabels()); + $recommendationRiskData['vulnerability'] = array_merge([ + 'uuid' => $recommendationRisk->getVulnerability()->getUuid(), + 'code' => $recommendationRisk->getVulnerability()->getCode(), + ], $recommendationRisk->getVulnerability()->getLabels()); + } + if ($recommendationRisk->getInstanceRisk()) { + $recommendationRiskData['instanceRisk'] = [ + 'id' => $recommendationRisk->getInstanceRisk()->getId(), + 'kindOfMeasure' => $recommendationRisk->getInstanceRisk()->getKindOfMeasure(), + 'cacheMaxRisk' => $recommendationRisk->getInstanceRisk()->getCacheMaxRisk(), + 'cacheTargetedRisk' => $recommendationRisk->getInstanceRisk()->getCacheTargetedRisk(), + 'comment' => $recommendationRisk->getInstanceRisk()->getComment(), + ]; + } + if ($recommendationRisk->getInstanceRiskOp()) { + $recommendationRiskData['instanceRiskOp'] = array_merge([ + 'id' => $recommendationRisk->getInstanceRiskOp()->getId(), + 'kindOfMeasure' => $recommendationRisk->getInstanceRiskOp()->getKindOfMeasure(), + 'cacheNetRisk' => $recommendationRisk->getInstanceRiskOp()->getCacheNetRisk(), + 'cacheTargetedRisk' => $recommendationRisk->getInstanceRiskOp()->getCacheTargetedRisk(), + 'rolfRisk' => [ + 'id' => $recommendationRisk->getInstanceRiskOp()->getRolfRisk()?->getId(), + ], + 'comment' => $recommendationRisk->getInstanceRiskOp()->getComment(), + ], $recommendationRisk->getInstanceRiskOp()->getRiskCacheLabels()); + } + } + + return $recommendationRiskData; + } +} diff --git a/src/Service/AnrRecommendationService.php b/src/Service/AnrRecommendationService.php new file mode 100755 index 00000000..9d0133d6 --- /dev/null +++ b/src/Service/AnrRecommendationService.php @@ -0,0 +1,321 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $formattedInputParams): array + { + $recommendationsData = []; + /** @var Entity\Recommendation $recommendation */ + foreach ($this->recommendationTable->findByParams($formattedInputParams) as $recommendation) { + $recommendationsData[] = $this->getPreparedRecommendationData($recommendation); + } + + return $recommendationsData; + } + + public function getCount(FormattedInputParams $formattedInputParams): int + { + return $this->recommendationTable->countByParams($formattedInputParams); + } + + public function getRecommendationData(Entity\Anr $anr, string $uuid): array + { + /** @var Entity\Recommendation $recommendation */ + $recommendation = $this->recommendationTable->findByUuidAndAnr($uuid, $anr); + + return $this->getPreparedRecommendationData($recommendation); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\Recommendation + { + /** @var Entity\RecommendationSet $recommendationSet */ + $recommendationSet = $data['recommendationSet'] instanceof Entity\RecommendationSet + ? $data['recommendationSet'] + : $this->recommendationSetTable->findByUuidAndAnr($data['recommendationSet'], $anr); + + $recommendation = (new Entity\Recommendation()) + ->setAnr($anr) + ->setRecommendationSet($recommendationSet) + ->setImportance($data['importance'] ?? Entity\Recommendation::EMPTY_IMPORTANCE) + ->setCode($data['code']) + ->setDescription($data['description']) + ->setCreator($this->connectedUser->getEmail()); + if (!empty($data['uuid'])) { + /* The UUID is set only when it's imported from MOSP or duplicated on anr creation. */ + $recommendation->setUuid($data['uuid']); + } + if (isset($data['position'])) { + $recommendation->setPosition($data['position']); + } + if (isset($data['comment'])) { + $recommendation->setComment($data['comment']); + } + if (isset($data['status'])) { + $recommendation->setStatus($data['status']); + } + if (isset($data['responsible']) || isset($data['responsable'])) { + $recommendation->setResponsible($data['responsible'] ?? $data['responsable']); + } + if (!empty($data['duedate'])) { + if ($data['duedate'] instanceof DateTime) { + $recommendation->setDueDate($data['duedate']); + } else { + if (\is_array($data['duedate'])) { + $data['duedate'] = $data['duedate']['date']; + } + $recommendation->setDueDateFromString($data['duedate']); + } + } + if (isset($data['counterTreated'])) { + $recommendation->setCounterTreated($data['counterTreated']); + } + + $this->recommendationTable->save($recommendation, $saveInDb); + + return $recommendation; + } + + /** + * @return string[] + */ + public function createList(Entity\Anr $anr, array $data): array + { + $createdUuids = []; + foreach ($data as $recommendationData) { + $createdUuids[] = $this->create($anr, $recommendationData, false)->getUuid(); + } + $this->recommendationTable->flush(); + + return $createdUuids; + } + + public function patch(Entity\Anr $anr, string $uuid, array $data): Entity\Recommendation + { + /** @var Entity\Recommendation $recommendation */ + $recommendation = $this->recommendationTable->findByUuidAndAnr($uuid, $anr); + + if (!empty($data['duedate'])) { + if ($data['duedate'] instanceof DateTime) { + $recommendation->setDueDate($data['duedate']); + } else { + if (\is_array($data['duedate'])) { + $data['duedate'] = $data['duedate']['date']; + } + $recommendation->setDueDateFromString($data['duedate']); + } + } elseif (isset($data['duedate']) && $data['duedate'] === '') { + $recommendation->setDueDate(null); + } + + if (!empty($data['recommendationSet']) + && $data['recommendationSet'] !== $recommendation->getRecommendationSet()->getUuid() + ) { + /** @var Entity\RecommendationSet $recommendationSet */ + $recommendationSet = $this->recommendationSetTable->findByUuidAndAnr($data['recommendationSet'], $anr); + $recommendation->setRecommendationSet($recommendationSet); + } + + if (!empty($data['code']) && $data['code'] !== $recommendation->getCode()) { + $recommendation->setCode($data['code']); + } + if (!empty($data['description']) && $data['description'] !== $recommendation->getDescription()) { + $recommendation->setDescription($data['description']); + } + $isImportanceChanged = false; + if (!empty($data['importance']) && $recommendation->getImportance() !== $data['importance']) { + $isImportanceChanged = true; + $recommendation->setImportance($data['importance']); + } + if (isset($data['status']) && $recommendation->getStatus() !== (int)$data['status']) { + $recommendation->setStatus((int)$data['status']); + } + if (!empty($data['comment']) && $recommendation->getComment() !== $data['comment']) { + $recommendation->setComment($data['comment']); + } + if (!empty($data['responsable']) && $recommendation->getResponsible() !== $data['responsable']) { + $recommendation->setResponsible($data['responsable']); + } + if (!empty($data['position']) && $recommendation->getPosition() !== $data['position']) { + $recommendation->setPosition($data['position']); + } + + $this->recommendationTable->save($recommendation->setUpdater($this->connectedUser->getEmail())); + + $this->updatePositions($recommendation, $data, $isImportanceChanged); + + return $recommendation; + } + + public function delete(Entity\Anr $anr, string $uuid): void + { + /** @var Entity\Recommendation $recommendation */ + $recommendation = $this->recommendationTable->findByUuidAndAnr($uuid, $anr); + + if (!$recommendation->isPositionEmpty()) { + $this->resetRecommendationsPositions($anr, [$recommendation->getUuid() => $recommendation]); + } + + $this->recommendationTable->remove($recommendation); + } + + /** + * Updates the position of the recommendation, based on the implicitPosition and/or previous field passed in $data. + */ + private function updatePositions( + Entity\Recommendation $recommendation, + array $data, + bool $isImportanceChanged + ): void { + if (!empty($data['implicitPosition'])) { + $newPosition = $recommendation->getPosition(); + + $linkedRecommendations = $this->recommendationTable + ->findLinkedWithRisksByAnrWithSpecifiedImportanceAndPositionAndExcludeRecommendations( + $recommendation->getAnr(), + [$recommendation->getUuid()], + ['r.position' => 'ASC'] + ); + + switch ($data['implicitPosition']) { + case PositionUpdatableServiceInterface::IMPLICIT_POSITION_START: + foreach ($linkedRecommendations as $linkedRecommendation) { + if ($linkedRecommendation->isPositionHigherThan($recommendation->getPosition()) + && !$linkedRecommendation->isPositionLowerThan($recommendation->getPosition()) + ) { + $this->recommendationTable->save($linkedRecommendation->shiftPositionDown(), false); + } + } + $newPosition = 1; + break; + case PositionUpdatableServiceInterface::IMPLICIT_POSITION_END: + $maxPosition = 1; + foreach ($linkedRecommendations as $linkedRecommendation) { + if ($linkedRecommendation->isPositionLowerThan($recommendation->getPosition())) { + $maxPosition = $linkedRecommendation->getPosition(); + $this->recommendationTable->save($linkedRecommendation->shiftPositionUp(), false); + } + } + $newPosition = $maxPosition; + break; + case PositionUpdatableServiceInterface::IMPLICIT_POSITION_AFTER: + if (!empty($data['previous'])) { + /** @var Entity\Recommendation $previousRecommendation */ + $previousRecommendation = $this->recommendationTable->findByUuidAndAnr( + $data['previous'], + $recommendation->getAnr() + ); + $isRecommendationMovedUp = $previousRecommendation->isPositionHigherThan( + $recommendation->getPosition() + ); + $newPosition = $isRecommendationMovedUp ? $previousRecommendation->getPosition() + 1 + : $previousRecommendation->getPosition(); + + foreach ($linkedRecommendations as $linkedRecommendation) { + if ($isRecommendationMovedUp + && $linkedRecommendation->isPositionLowerThan($previousRecommendation->getPosition()) + && $linkedRecommendation->isPositionHigherThan($recommendation->getPosition()) + ) { + $this->recommendationTable->save( + $linkedRecommendation->shiftPositionDown(), + false + ); + } elseif (!$isRecommendationMovedUp + && $linkedRecommendation->isPositionLowerThan($recommendation->getPosition()) + && $linkedRecommendation->isPositionHigherOrEqualThan( + $previousRecommendation->getPosition() + ) + ) { + $this->recommendationTable->save($linkedRecommendation->shiftPositionUp(), false); + } + } + } + break; + } + $this->recommendationTable->save($recommendation->setPosition($newPosition)); + } elseif ($isImportanceChanged && $recommendation->hasLinkedRecommendationRisks()) { + $recommendationRisk = $recommendation->getRecommendationRisks()->first(); + $linkedRisk = $recommendationRisk->getInstanceRisk() ?? $recommendationRisk->getInstanceRiskOp(); + $this->updateInstanceRiskRecommendationsPositions($linkedRisk); + } + } + + /** + * Computes the due date color for the recommendation. + * Returns 'no-date' if no due date is set on the recommendation, 'large' if there's a lot of time remaining, + * 'warning' if there is less than 15 days remaining, and 'alert' if the due date is in the past. + * + * @return string 'no-date', 'large', 'warning', 'alert' + */ + private function getDueDateColor(?DateTime $dueDate): string + { + if ($dueDate === null) { + return 'no-date'; + } + + $diff = $dueDate->getTimestamp() - time(); + if ($diff < 0) { + return "alert"; + } + /* arbitrary 15 days */ + $days = round($diff / 60 / 60 / 24); + if ($days <= 15) { + return "warning"; + } + + return "large"; + } + + private function getPreparedRecommendationData(Entity\Recommendation $recommendation): array + { + return [ + 'uuid' => $recommendation->getUuid(), + 'recommendationSet' => [ + 'uuid' => $recommendation->getRecommendationSet()->getUuid(), + 'label' => $recommendation->getRecommendationSet()->getLabel(), + ], + 'code' => $recommendation->getCode(), + 'comment' => $recommendation->getComment(), + 'description' => $recommendation->getDescription(), + 'duedate' => $recommendation->getDueDate() === null ? '' + : ['date' => $recommendation->getDueDate()->format('Y-m-d')], + 'importance' => $recommendation->getImportance(), + 'position' => $recommendation->getPosition(), + 'responsable' => $recommendation->getResponsible(), + 'status' => $recommendation->getStatus(), + 'timerColor' => $this->getDueDateColor($recommendation->getDueDate()), + 'counterTreated' => $recommendation->getCounterTreated() === 0 + ? 'COMING' + : '_SMILE_IN_PROGRESS (' . $recommendation->getCounterTreated() . ')' + ]; + } +} diff --git a/src/Service/AnrRecommendationSetService.php b/src/Service/AnrRecommendationSetService.php new file mode 100644 index 00000000..1c48deee --- /dev/null +++ b/src/Service/AnrRecommendationSetService.php @@ -0,0 +1,121 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(Anr $anr) + { + $recommendationSetsList = []; + /** @var RecommendationSet $recommendationSet */ + foreach ($this->recommendationSetTable->findByAnr($anr) as $recommendationSet) { + $recommendationSetsList[] = $this->getPreparedRecommendationSetData($recommendationSet); + } + + return $recommendationSetsList; + } + + public function getRecommendationSetData(Anr $anr, string $uuid): array + { + /** @var RecommendationSet $recommendationSet */ + $recommendationSet = $this->recommendationSetTable->findByUuidAndAnr($uuid, $anr); + + return $this->getPreparedRecommendationSetData($recommendationSet); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): RecommendationSet + { + $recommendationSet = (new RecommendationSet()) + ->setAnr($anr) + ->setLabel($data['label']) + ->setCreator($this->connectedUser->getEmail()); + if (!empty($data['uuid'])) { + /* The UUID is set only when it's imported from MOSP or duplicated on anr creation. */ + $recommendationSet->setUuid($data['uuid']); + } + + $this->recommendationSetTable->save($recommendationSet, $saveInDb); + + return $recommendationSet; + } + + public function getOrCreate(Anr $anr, array $data, bool $saveInDb = true): RecommendationSet + { + if (!empty($data['uuid'])) { + /** @var RecommendationSet|null $recommendationSet */ + $recommendationSet = $this->recommendationSetTable->findByUuidAndAnr($data['uuid'], $anr, false); + if ($recommendationSet !== null) { + return $recommendationSet; + } + } + + return $this->create($anr, $data, $saveInDb); + } + + public function patch(Anr $anr, string $uuid, array $data): RecommendationSet + { + /** @var RecommendationSet $recommendationSet */ + $recommendationSet = $this->recommendationSetTable->findByUuidAndAnr($uuid, $anr); + if ($data['label'] !== $recommendationSet->getLabel()) { + $recommendationSet->setLabel($data['label']) + ->setUpdater($this->connectedUser->getEmail()); + + $this->recommendationSetTable->save($recommendationSet); + } + + return $recommendationSet; + } + + public function delete(Anr $anr, string $uuid): void + { + /** @var RecommendationSet $recommendationSet */ + $recommendationSet = $this->recommendationSetTable->findByUuidAndAnr($uuid, $anr); + + $recommendationsToResetPositions = []; + foreach ($recommendationSet->getRecommendations() as $recommendation) { + if (!$recommendation->isPositionEmpty()) { + $recommendationsToResetPositions[$recommendation->getUuid()] = $recommendation; + } + } + if (!empty($recommendationsToResetPositions)) { + $this->resetRecommendationsPositions($anr, $recommendationsToResetPositions); + } + + $this->recommendationSetTable->remove($recommendationSet); + } + + private function getPreparedRecommendationSetData(RecommendationSet $recommendationSet): array + { + return [ + 'uuid' => $recommendationSet->getUuid(), + 'label' => $recommendationSet->getLabel(), + 'anr' => [ + 'id' => $recommendationSet->getAnr()->getId(), + ], + ]; + } +} diff --git a/src/Service/AnrRecordActorService.php b/src/Service/AnrRecordActorService.php index ca1c7790..828cf89f 100644 --- a/src/Service/AnrRecordActorService.php +++ b/src/Service/AnrRecordActorService.php @@ -75,7 +75,7 @@ public function generateExportArray($id) /** * Imports a record actor from a data array. This data is generally what has been exported into a file. * @param array $data The record actor's data fields - * @param \Monarc\FrontOffice\Model\Entity\Anr $anr The target ANR id + * @param \Monarc\FrontOffice\Entity\Anr $anr The target ANR id * @return bool|int The ID of the generated asset, or false if an error occurred. */ public function importFromArray($data, $anr) @@ -87,7 +87,7 @@ public function importFromArray($data, $anr) try { $actorEntity = $this->get('table')->getEntityByFields(['label' => $data['label'], 'anr' => $anr]); if (count($actorEntity)) { - $id = $actorEntity[0]->get('id'); + $id = $actorEntity[0]->getId(); } else { $id = $this->create($data); } diff --git a/src/Service/AnrRecordActorServiceFactory.php b/src/Service/AnrRecordActorServiceFactory.php index 058ae1f9..f2a4c8e1 100644 --- a/src/Service/AnrRecordActorServiceFactory.php +++ b/src/Service/AnrRecordActorServiceFactory.php @@ -8,6 +8,7 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Record Actor Service Factory @@ -19,8 +20,8 @@ class AnrRecordActorServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\RecordActorTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\RecordActor', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', + 'entity' => 'Monarc\FrontOffice\Entity\RecordActor', + 'userAnrTable' => UserAnrTable::class, 'recordTable' => 'Monarc\FrontOffice\Model\Table\RecordTable', 'processorTable' => 'Monarc\FrontOffice\Model\Table\RecordProcessorTable', ]; diff --git a/src/Service/AnrRecordDataCategoryService.php b/src/Service/AnrRecordDataCategoryService.php index 39a80cb3..50474d20 100644 --- a/src/Service/AnrRecordDataCategoryService.php +++ b/src/Service/AnrRecordDataCategoryService.php @@ -29,9 +29,9 @@ class AnrRecordDataCategoryService extends AbstractService */ public function createDataCategory($data) { - $dc = $this->get('table')->getEntityByFields(['label' => $data['label'], 'anr' => $data['anr']->get('id')]); + $dc = $this->get('table')->getEntityByFields(['label' => $data['label'], 'anr' => $data['anr']->getId()]); if(count($dc)) { - return $dc[0]->get('id'); + return $dc[0]->getId(); } return $this->create($data, true); } @@ -66,7 +66,7 @@ public function generateExportArray($id) /** * Imports a record data category from a data array. This data is generally what has been exported into a file. * @param array $data The record data category's data fields - * @param \Monarc\FrontOffice\Model\Entity\Anr $anr The target ANR id + * @param \Monarc\FrontOffice\Entity\Anr $anr The target ANR id * @return bool|int The ID of the generated asset, or false if an error occurred. */ public function importFromArray($data, $anr) @@ -77,7 +77,7 @@ public function importFromArray($data, $anr) try { $dataCategoryEntity = $this->get('table')->getEntityByFields(['label' => $data['label'], 'anr' => $anr]); if (count($dataCategoryEntity)) { - $id = $dataCategoryEntity[0]->get('id'); + $id = $dataCategoryEntity[0]->getId(); } else { $id = $this->create($data); } diff --git a/src/Service/AnrRecordDataCategoryServiceFactory.php b/src/Service/AnrRecordDataCategoryServiceFactory.php index 2c401463..4874acc9 100644 --- a/src/Service/AnrRecordDataCategoryServiceFactory.php +++ b/src/Service/AnrRecordDataCategoryServiceFactory.php @@ -8,6 +8,7 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Record Data Category Service Factory @@ -19,8 +20,8 @@ class AnrRecordDataCategoryServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\RecordDataCategoryTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\RecordDataCategory', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', + 'entity' => 'Monarc\FrontOffice\Entity\RecordDataCategory', + 'userAnrTable' => UserAnrTable::class, 'personalDataTable' => 'Monarc\FrontOffice\Model\Table\RecordPersonalDataTable', ]; } diff --git a/src/Service/AnrRecordInternationalTransferService.php b/src/Service/AnrRecordInternationalTransferService.php index 9397acfb..51e146ba 100644 --- a/src/Service/AnrRecordInternationalTransferService.php +++ b/src/Service/AnrRecordInternationalTransferService.php @@ -56,7 +56,7 @@ public function generateExportArray($id) /** * Imports a record international transfer from a data array. This data is generally what has been exported into a file. * @param array $data The record international transfer's data fields - * @param \Monarc\FrontOffice\Model\Entity\Anr $anr The target ANR id + * @param \Monarc\FrontOffice\Entity\Anr $anr The target ANR id * @param int $parentId The id of the entity possessing this international transfer * @return bool|int The ID of the generated asset, or false if an error occurred. */ diff --git a/src/Service/AnrRecordInternationalTransferServiceFactory.php b/src/Service/AnrRecordInternationalTransferServiceFactory.php index 82e93b31..e74318ac 100644 --- a/src/Service/AnrRecordInternationalTransferServiceFactory.php +++ b/src/Service/AnrRecordInternationalTransferServiceFactory.php @@ -8,6 +8,10 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\UserAnrTable; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Entity\RecordInternationalTransfer; +use Monarc\FrontOffice\Model\Table\RecordInternationalTransferTable; /** * Record International Transfer Service Factory @@ -18,9 +22,9 @@ class AnrRecordInternationalTransferServiceFactory extends AbstractServiceFactory { protected $ressources = [ - 'table' => 'Monarc\FrontOffice\Model\Table\RecordInternationalTransferTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\RecordInternationalTransfer', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', + 'table' => RecordInternationalTransferTable::class, + 'entity' => RecordInternationalTransfer::class, + 'userAnrTable' => UserAnrTable::class, + 'anrTable' => AnrTable::class, ]; } diff --git a/src/Service/AnrRecordPersonalDataService.php b/src/Service/AnrRecordPersonalDataService.php index 8757d312..d4b11f6a 100644 --- a/src/Service/AnrRecordPersonalDataService.php +++ b/src/Service/AnrRecordPersonalDataService.php @@ -35,7 +35,7 @@ public function createPersonalData($data) if (!empty($data['dataCategories'])) { foreach ($data['dataCategories'] as $dataCategory) { if (!isset($dataCategory['id'])) { - $dc['anr'] = $this->anrTable->getEntity($data['anr']); + $dc['anr'] = $this->anrTable->findById((int)$data['anr']); $dc['id'] = $this->recordDataCategoryService->createDataCategory($dataCategory); } $dataCategories[] = $dataCategory['id']; @@ -49,7 +49,7 @@ public function createPersonalData($data) public function deletePersonalData($id) { $personalDataEntity = $this->get('table')->getEntity($id); - $anrId = $personalDataEntity->anr->id; + $anrId = $personalDataEntity->getAnr()->getId(); $dataCategoriesToCheck = []; foreach($personalDataEntity->dataCategories as $dc) { $dataCategoriesToCheck[] = $dc->id; @@ -76,7 +76,7 @@ public function updatePersonalData($id, $data) if (!empty($data['dataCategories'])) { foreach ($data['dataCategories'] as $dc) { if (!isset($dc['id'])) { - $dc['anr'] = $this->anrTable->getEntity($data['anr']); + $dc['anr'] = $this->anrTable->findById((int)$data['anr']); $dc['id'] = $this->recordDataCategoryService->createDataCategory($dc); } $dataCategories[] = $dc['id']; @@ -141,7 +141,7 @@ public function generateExportArray($id) /** * Imports a record personal data from a data array. This data is generally what has been exported into a file. * @param array $data The record personal data's data fields - * @param \Monarc\FrontOffice\Model\Entity\Anr $anr The target ANR id + * @param \Monarc\FrontOffice\Entity\Anr $anr The target ANR id * @return bool|int The ID of the generated asset, or false if an error occurred. */ public function importFromArray($data, $anr, $recordId) diff --git a/src/Service/AnrRecordPersonalDataServiceFactory.php b/src/Service/AnrRecordPersonalDataServiceFactory.php index 0f694bc4..6958f548 100644 --- a/src/Service/AnrRecordPersonalDataServiceFactory.php +++ b/src/Service/AnrRecordPersonalDataServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Record Personal Data Service Factory @@ -19,9 +21,9 @@ class AnrRecordPersonalDataServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\RecordPersonalDataTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\RecordPersonalData', + 'entity' => 'Monarc\FrontOffice\Entity\RecordPersonalData', 'recordDataCategoryService' => 'Monarc\FrontOffice\Service\AnrRecordDataCategoryService', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', + 'userAnrTable' => UserAnrTable::class, + 'anrTable' => AnrTable::class, ]; } diff --git a/src/Service/AnrRecordProcessorService.php b/src/Service/AnrRecordProcessorService.php index 2bb1dcec..923ef4fc 100644 --- a/src/Service/AnrRecordProcessorService.php +++ b/src/Service/AnrRecordProcessorService.php @@ -9,7 +9,7 @@ use Monarc\Core\Exception\Exception; use Monarc\Core\Service\AbstractService; -use Monarc\FrontOffice\Model\Entity\RecordProcessor; +use Monarc\FrontOffice\Entity\RecordProcessor; /** * AnrRecord Processor Service @@ -29,7 +29,7 @@ class AnrRecordProcessorService extends AbstractService public function deleteProcessor($id) { $entity = $this->get('table')->getEntity($id); - $anrId = $entity->anr->id; + $anrId = $entity->getAnr()->getId(); $actorsToCheck = array(); if($entity->dpo) { array_push($actorsToCheck, $entity->dpo->id); @@ -145,7 +145,7 @@ public function orphanProcessor($processorId, $anrId) { /** * Imports a record processor from a data array. This data is generally what has been exported into a file. * @param array $data The processor's data fields - * @param \Monarc\FrontOffice\Model\Entity\Anr $anr The target ANR id + * @param \Monarc\FrontOffice\Entity\Anr $anr The target ANR id * @return bool|int The ID of the generated asset, or false if an error occurred. */ public function importFromArray($data, $anr) @@ -158,7 +158,7 @@ public function importFromArray($data, $anr) try { $processorEntity = $this->get('table')->getEntityByFields(['label' => $newData['label'], 'anr' => $anr]); if (count($processorEntity)) { - $id = $processorEntity[0]->get('id'); + $id = $processorEntity[0]->getId(); } else { $id = $this->create($newData); } diff --git a/src/Service/AnrRecordProcessorServiceFactory.php b/src/Service/AnrRecordProcessorServiceFactory.php index 2787299f..250e790a 100644 --- a/src/Service/AnrRecordProcessorServiceFactory.php +++ b/src/Service/AnrRecordProcessorServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\UserAnrTable; +use Monarc\FrontOffice\Table\AnrTable; /** * Record Processor Service Factory @@ -19,10 +21,10 @@ class AnrRecordProcessorServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\RecordProcessorTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\RecordProcessor', + 'entity' => 'Monarc\FrontOffice\Entity\RecordProcessor', 'recordActorService' => 'Monarc\FrontOffice\Service\AnrRecordActorService', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', + 'userAnrTable' => UserAnrTable::class, + 'anrTable' => AnrTable::class, 'recordTable' => 'Monarc\FrontOffice\Model\Table\RecordTable', ]; } diff --git a/src/Service/AnrRecordRecipientService.php b/src/Service/AnrRecordRecipientService.php index c4501d2d..a6146c67 100644 --- a/src/Service/AnrRecordRecipientService.php +++ b/src/Service/AnrRecordRecipientService.php @@ -58,7 +58,7 @@ public function generateExportArray($id) /** * Imports a record recipient from a data array. This data is generally what has been exported into a file. * @param array $data The record recipient's data fields - * @param \Monarc\FrontOffice\Model\Entity\Anr $anr The target ANR id + * @param \Monarc\FrontOffice\Entity\Anr $anr The target ANR id * @return bool|int The ID of the generated asset, or false if an error occurred. */ public function importFromArray($data, $anr) @@ -76,7 +76,7 @@ public function importFromArray($data, $anr) 'anr' => $anr ]); if (count($recipientEntity)) { - $id = $recipientEntity[0]->get('id'); + $id = $recipientEntity[0]->getId(); } else { $id = $this->create($data); } diff --git a/src/Service/AnrRecordRecipientServiceFactory.php b/src/Service/AnrRecordRecipientServiceFactory.php index db82a769..4b24f5cd 100644 --- a/src/Service/AnrRecordRecipientServiceFactory.php +++ b/src/Service/AnrRecordRecipientServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\UserAnrTable; +use Monarc\FrontOffice\Table\AnrTable; /** * Record Recipient Service Factory @@ -19,9 +21,9 @@ class AnrRecordRecipientServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\RecordRecipientTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\RecordRecipient', + 'entity' => 'Monarc\FrontOffice\Entity\RecordRecipient', 'recordTable' => 'Monarc\FrontOffice\Model\Table\RecordTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', + 'userAnrTable' => UserAnrTable::class, + 'anrTable' => AnrTable::class, ]; } diff --git a/src/Service/AnrRecordService.php b/src/Service/AnrRecordService.php index a77d8874..c0e58132 100644 --- a/src/Service/AnrRecordService.php +++ b/src/Service/AnrRecordService.php @@ -8,11 +8,11 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Exception\Exception; +use Monarc\Core\Helper\EncryptDecryptHelperTrait; use Monarc\Core\Service\AbstractService; -use Monarc\FrontOffice\Model\Entity\Anr; -use Monarc\FrontOffice\Model\Entity\Record; -use Monarc\FrontOffice\Model\Entity\RecordInternationalTransfer; -use Monarc\FrontOffice\Model\Entity\RecordPersonalData; +use Monarc\FrontOffice\Entity\Record; +use Monarc\FrontOffice\Entity\RecordInternationalTransfer; +use Monarc\FrontOffice\Entity\RecordPersonalData; /** * AnrRecord Service @@ -22,9 +22,20 @@ */ class AnrRecordService extends AbstractService { - protected $dependencies = [ 'anr', 'controller', 'representative', 'dpo', 'jointControllers', - 'personalData', 'internationalTransfers', 'processors', 'recipients']; - protected $filterColumns = [ 'label' ]; + use EncryptDecryptHelperTrait; + + protected $dependencies = [ + 'anr', + 'controller', + 'representative', + 'dpo', + 'jointControllers', + 'personalData', + 'internationalTransfers', + 'processors', + 'recipients', + ]; + protected $filterColumns = ['label']; protected $recordActorService; protected $recordProcessorService; protected $recordRecipientService; @@ -42,53 +53,53 @@ class AnrRecordService extends AbstractService public function deleteRecord($id) { $entity = $this->get('table')->getEntity($id); - $anrId = $entity->anr->id; + $anrId = $entity->getAnr()->getId(); $actorsToCheck = []; $processorsToCheck = []; $recipientsToCheck = []; - if($entity->controller) { + if ($entity->controller) { $actorsToCheck[] = $entity->controller->id; } - if($entity->dpo) { + if ($entity->dpo) { $actorsToCheck[] = $entity->dpo->id; } - if($entity->representative) { + if ($entity->representative) { $actorsToCheck[] = $entity->representative->id; } - foreach($entity->jointControllers as $jc) { + foreach ($entity->jointControllers as $jc) { $actorsToCheck[] = $jc->id; } - foreach($entity->processors as $p) { + foreach ($entity->processors as $p) { $processorsToCheck[] = $p->id; } - foreach($entity->recipients as $r) { + foreach ($entity->recipients as $r) { $recipientsToCheck[] = $r->id; } - foreach($entity->personalData as $pd) { - $this->recordPersonalDataService->deletePersonalData(['anr'=> $anrId, 'id' => $pd->id]); + foreach ($entity->personalData as $pd) { + $this->recordPersonalDataService->deletePersonalData(['anr' => $anrId, 'id' => $pd->id]); } - foreach($entity->internationalTransfers as $it) { - $this->recordInternationalTransferService->delete(['anr'=> $anrId, 'id' => $it->id]); + foreach ($entity->internationalTransfers as $it) { + $this->recordInternationalTransferService->delete(['anr' => $anrId, 'id' => $it->id]); } $result = $this->get('table')->delete($id); $actorsToCheck = array_unique($actorsToCheck); - foreach($actorsToCheck as $a) { - if($this->recordActorService->orphanActor($a, $anrId)) { - $this->recordActorService->delete(['anr'=> $anrId, 'id' => $a]); + foreach ($actorsToCheck as $a) { + if ($this->recordActorService->orphanActor($a, $anrId)) { + $this->recordActorService->delete(['anr' => $anrId, 'id' => $a]); } } $processorsToCheck = array_unique($processorsToCheck); - foreach($processorsToCheck as $p) { - if($this->recordProcessorService->orphanProcessor($p, $anrId)) { + foreach ($processorsToCheck as $p) { + if ($this->recordProcessorService->orphanProcessor($p, $anrId)) { $this->recordProcessorService->deleteProcessor($p); } else { $this->recordProcessorService->deleteActivityAndSecMeasure($p, $id); } } $recipientsToCheck = array_unique($recipientsToCheck); - foreach($recipientsToCheck as $r) { - if($this->recordRecipientService->orphanRecipient($r, $anrId)) { - $this->recordRecipientService->delete(['anr'=> $anrId, 'id' => $r]); + foreach ($recipientsToCheck as $r) { + if ($this->recordRecipientService->orphanRecipient($r, $anrId)) { + $this->recordRecipientService->delete(['anr' => $anrId, 'id' => $r]); } } @@ -97,7 +108,9 @@ public function deleteRecord($id) /** * Updates a record of processing activity + * * @param array $data The record details fields + * * @return object The resulting created record object (entity) */ public function updateRecord($id, $data) @@ -105,106 +118,121 @@ public function updateRecord($id, $data) $entity = $this->get('table')->getEntity($id); // keep entities on old object to delete orphans - $oldActors = array(); - if($entity->controller && $entity->controller->id) { + $oldActors = []; + if ($entity->controller && $entity->controller->id) { $oldActors[] = $entity->controller->id; } - if($entity->representative && $entity->representative->id) { + if ($entity->representative && $entity->representative->id) { $oldActors[] = $entity->representative->id; } - if($entity->dpo && $entity->dpo->id) { + if ($entity->dpo && $entity->dpo->id) { $oldActors[] = $entity->dpo->id; } - foreach($entity->jointControllers as $js) { + foreach ($entity->jointControllers as $js) { $oldActors[] = $js->id; } - $oldRecipients = array(); - foreach( $entity->recipients as $r) { + $oldRecipients = []; + foreach ($entity->recipients as $r) { $oldRecipients[] = $r->id; } - $oldProcessors = array(); - foreach( $entity->processors as $p) { + $oldProcessors = []; + foreach ($entity->processors as $p) { $oldProcessors[] = $p->id; } - if(isset($data['controller']['id'])) { + if (isset($data['controller']['id'])) { $data['controller'] = $data['controller']['id']; } else { $data['controller'] = null; } - if(isset($data['dpo']['id'])) { + if (isset($data['dpo']['id'])) { $data['dpo'] = $data['dpo']['id']; } else { $data['dpo'] = null; } - if(isset($data['representative']['id'])) { + if (isset($data['representative']['id'])) { $data['representative'] = $data['representative']['id']; } else { $data['representative'] = null; } - $jointControllers = array(); + + $jointControllers = []; foreach ($data['jointControllers'] as $jc) { $jointControllers[] = $jc['id']; } $data['jointControllers'] = $jointControllers; - $personalData = array(); + $personalData = []; foreach ($data['personalData'] as $pd) { $personalData[] = $pd['id']; } $data['personalData'] = $personalData; - $recipients = array(); + + $recipients = []; foreach ($data['recipients'] as $recipient) { $recipients[] = $recipient['id']; } $data['recipients'] = $recipients; - $internationalTransfers = array(); + + $internationalTransfers = []; foreach ($data['internationalTransfers'] as $it) { $internationalTransfers[] = $it['id']; } $data['internationalTransfers'] = $internationalTransfers; - $processors = array(); + + $processors = []; foreach ($data['processors'] as $processor) { $processors[] = $processor['id']; } $data['processors'] = $processors; - foreach($entity->personalData as $pd) { - if(!in_array($pd->id, $personalData)) { - $this->recordPersonalDataService->deletePersonalData(['anr'=> $data['anr'], 'id' => $pd->id]); + foreach ($entity->personalData as $pd) { + if (!in_array($pd->id, $data['personalData'])) { + $this->recordPersonalDataService->deletePersonalData(['anr' => $data['anr'], 'id' => $pd->id]); } } - foreach($entity->internationalTransfers as $it) { - if(!in_array($it->id, $internationalTransfers)) { - $this->recordInternationalTransferService->delete(['anr'=> $data['anr'], 'id' => $it->id]); + foreach ($entity->internationalTransfers as $it) { + if (!in_array($it->id, $data['internationalTransfers'])) { + $this->recordInternationalTransferService->delete(['anr' => $data['anr'], 'id' => $it->id]); } } $result = $this->update($id, $data); - foreach($oldActors as $a) { - if(!in_array($a, $jointControllers) && $a != $data['controller'] && $a != $data['dpo'] && $a != $data['representative'] - && $this->recordActorService->orphanActor($a, $data['anr'])) { - $this->recordActorService->delete(['anr'=> $data['anr'], 'id' => $a]); + foreach ($oldActors as $a) { + if (!in_array($a, $data['jointControllers']) + && $a != $data['controller'] + && $a != $data['dpo'] + && $a != $data['representative'] + && $this->recordActorService->orphanActor($a, $data['anr']) + ) { + $this->recordActorService->delete(['anr' => $data['anr'], 'id' => $a]); } } - foreach($oldRecipients as $rc) { - if(!in_array($rc, $recipients) && $this->recordRecipientService->orphanRecipient($rc, $data['anr'])) { - $this->recordRecipientService->delete(['anr'=> $data['anr'], 'id' => $rc]); + foreach ($oldRecipients as $rc) { + if (!in_array($rc, $data['recipients']) + && $this->recordRecipientService->orphanRecipient($rc, $data['anr']) + ) { + $this->recordRecipientService->delete(['anr' => $data['anr'], 'id' => $rc]); } } - foreach($oldProcessors as $processor) { - if(!in_array($processor, $processors) && $this->recordProcessorService->orphanProcessor($processor, $data['anr'])) { + foreach ($oldProcessors as $processor) { + if (!in_array($processor, $data['processors']) + && $this->recordProcessorService->orphanProcessor($processor, $data['anr']) + ) { $this->recordProcessorService->deleteProcessor($processor); - } else if (!in_array($processor, $processors)) { + } elseif (!in_array($processor, $data['processors'])) { $this->recordProcessorService->deleteActivityAndSecMeasure($processor, $id); } } + return $result; } /** * Duplicates an existing record in the anr + * * @param int $recordId The id of record to clone, either its ID or the object + * * @return int The newly created record id * @throws Exception */ @@ -214,9 +242,9 @@ public function duplicateRecord($recordId, $newLabel) $newRecord = new Record($entity); $newRecord->setId(null); $newRecord->resetUpdatedAtValue(); - $newRecord->setLabel($newLabel); + $newRecord->setLabel((string)$newLabel); $id = $this->get('table')->save($newRecord); - if($entity->getProcessors()) { + if ($entity->getProcessors()) { foreach ($entity->getProcessors() as $p) { $data = []; $activities = $p->getActivities(); @@ -226,7 +254,7 @@ public function duplicateRecord($recordId, $newLabel) $processor["id"] = $this->recordProcessorService->importActivityAndSecMeasures($data, $p->getId()); } } - if($entity->getPersonalData()) { + if ($entity->getPersonalData()) { foreach ($entity->getPersonalData() as $pd) { $newPersonalData = new RecordPersonalData($pd); $newPersonalData->setId(null); @@ -234,7 +262,7 @@ public function duplicateRecord($recordId, $newLabel) $this->get('personalDataTable')->save($newPersonalData); } } - if($entity->getInternationalTransfers()) { + if ($entity->getInternationalTransfers()) { foreach ($entity->getInternationalTransfers() as $it) { $newInternationalTransfer = new RecordInternationalTransfer($it); $newInternationalTransfer->setId(null); @@ -242,46 +270,53 @@ public function duplicateRecord($recordId, $newLabel) $this->get('internationalTransferTable')->save($newInternationalTransfer); } } + return $id; } /** * Exports a Record of processing activities, optionaly encrypted, for later re-import + * * @param array $data An array with the Record 'id' and 'password' for encryption + * * @return string JSON file, optionally encrypted */ public function export(&$data) { $filename = ""; - $exportedRecords = array(); $elem = $this->generateExportArray($data['id'], $filename); $exportedRecord = json_encode([$elem]); $data['filename'] = $filename; - if (! empty($data['password'])) { + if (!empty($data['password'])) { $exportedRecord = $this->encrypt($exportedRecord, $data['password']); } + return $exportedRecord; } - public function exportAll($data) { + public function exportAll($data) + { $recordEntities = $this->get('table')->getEntityByFields(['anr' => $data["anr"]]); - $exportedRecords = array(); - foreach($recordEntities as $entity) { + $exportedRecords = []; + foreach ($recordEntities as $entity) { $exportedRecords[] = $this->generateExportArray($entity->get("id")); } $exportedRecords = json_encode($exportedRecords); - if (! empty($data['password'])) { + if (!empty($data['password'])) { $exportedRecords = $this->encrypt($exportedRecords, $data['password']); } + return $exportedRecords; } /** * Generates the array to be exported into a file when calling {#exportRecord} * @see #exportRecord + * * @param int $id The record's id * @param string $filename The output filename + * * @return array The data array that should be saved * @throws Exception If the record is not found */ @@ -298,19 +333,19 @@ public function generateExportArray($id, &$filename = "") $return = [ 'name' => $entity->label, ]; - if($entity->controller) { + if ($entity->controller) { $return['controller'] = $this->recordActorService->generateExportArray($entity->controller->id); } - if($entity->representative) { + if ($entity->representative) { $return['representative'] = $this->recordActorService->generateExportArray($entity->representative->id); } - if($entity->dpo) { + if ($entity->dpo) { $return['data_protection_officer'] = $this->recordActorService->generateExportArray($entity->dpo->id); } - if($entity->purposes != '') { + if ($entity->purposes !== '') { $return['purposes'] = $entity->purposes; } - if($entity->secMeasures != '') { + if ($entity->secMeasures !== '') { $return['security_measures'] = $entity->secMeasures; } foreach ($entity->jointControllers as $jc) { @@ -323,19 +358,25 @@ public function generateExportArray($id, &$filename = "") $return['recipients'][] = $this->recordRecipientService->generateExportArray($r->id); } foreach ($entity->internationalTransfers as $it) { - $return['international_transfers'][] = $this->recordInternationalTransferService->generateExportArray($it->id); + $return['international_transfers'][] = $this->recordInternationalTransferService->generateExportArray( + $it->id + ); } foreach ($entity->processors as $p) { $return['processors'][] = $this->recordProcessorService->generateExportArray($p->id, $id); } + return $return; } /** * Imports a Record that has been exported into a file. + * * @param int $anrId The target ANR ID * @param array $data The data that has been posted to the API (file) - * @return array An array where the first key is an array of generated records' ID, and the second the eventual errors + * + * @return array An array where the first key is an array of generated records' ID, and the second the eventual + * errors * @throws Exception If the posted data is invalid, or ANR ID is invalid */ public function importFromFile($anrId, $data) @@ -346,8 +387,6 @@ public function importFromFile($anrId, $data) } $ids = $errors = []; - $anr = $this->get('anrTable')->getEntity($anrId); - if ($data['isJson'] == 'true') { $f = $data['file']; if (isset($f['error']) && $f['error'] === UPLOAD_ERR_OK && file_exists($f['tmp_name'])) { @@ -355,18 +394,24 @@ public function importFromFile($anrId, $data) if (empty($data['password'])) { $file = json_decode(trim(file_get_contents($f['tmp_name'])), true); if (!$file) { // support legacy export which were base64 encoded - $file = json_decode(trim($this->decrypt(base64_decode(file_get_contents($f['tmp_name'])), '')), true); + $file = json_decode( + trim($this->decrypt(base64_decode(file_get_contents($f['tmp_name'])), '')), + true + ); } } else { // Decrypt the file and store the JSON data as an array in memory $key = $data['password']; $file = json_decode(trim($this->decrypt(file_get_contents($f['tmp_name']), $key)), true); if (!$file) { // support legacy export which were base64 encoded - $file = json_decode(trim($this->decrypt(base64_decode(file_get_contents($f['tmp_name'])), $key)), true); + $file = json_decode( + trim($this->decrypt(base64_decode(file_get_contents($f['tmp_name'])), $key)), + true + ); } } - foreach($file as $key => $record) { + foreach ($file as $key => $record) { if ($record !== false && ($id = $this->importFromArray($record, $anrId)) !== false) { $ids[] = $id; } else { @@ -378,8 +423,8 @@ public function importFromFile($anrId, $data) $array = $data['csv']; $file = []; $file['type'] = 'record'; - foreach($array as $key => $row) { - if($key != 0 && trim($row["name"])) { + foreach ($array as $key => $row) { + if ($key != 0 && trim($row["name"])) { if ($file !== false && ($id = $this->importFromArray($file, $anrId)) !== false) { $ids[] = $id; } else { @@ -388,150 +433,166 @@ public function importFromFile($anrId, $data) $file = []; $file['type'] = 'record'; } - if(trim($row['name'])) { + if (trim($row['name'])) { $file['name'] = $row['name']; } - if(trim($row['purposes'])) { + if (trim($row['purposes'])) { $file['purposes'] = $row['purposes']; } - if(trim($row['security measures'])) { + if (trim($row['security measures'])) { $file['security_measures'] = $row['security measures']; } - if(trim($row['controller name'])) { + if (trim($row['controller name'])) { $file['controller'] = []; $file['controller']['name'] = $row['controller name']; - if(trim($row['controller contact'])) { + if (trim($row['controller contact'])) { $file['controller']['contact'] = $row['controller contact']; } } - if(trim($row['representative name'])) { + if (trim($row['representative name'])) { $file['representative'] = []; $file['representative']['name'] = $row['representative name']; - if(trim($row['representative contact'])) { + if (trim($row['representative contact'])) { $file['representative']['contact'] = $row['representative contact']; } } - if(trim($row['data protection officer name'])) { + if (trim($row['data protection officer name'])) { $file['data_protection_officer'] = []; $file['data_protection_officer']['name'] = $row['data protection officer name']; - if(trim($row['data protection officer contact'])) { + if (trim($row['data protection officer contact'])) { $file['data_protection_officer']['contact'] = $row['data protection officer contact']; } } - if(trim($row['joint controllers name'])) { - if( !isset($file['joint_controllers'])) { + if (trim($row['joint controllers name'])) { + if (!isset($file['joint_controllers'])) { $file['joint_controllers'] = []; } $jc = []; $jc['name'] = $row['joint controllers name']; - if(trim($row['joint controllers contact'])) { + if (trim($row['joint controllers contact'])) { $jc['contact'] = $row['joint controllers contact']; } $file['joint_controllers'][] = $jc; } - if(trim($row['retention period unit'])) { - if( !isset($file['personal_data'])) { + if (trim($row['retention period unit'])) { + if (!isset($file['personal_data'])) { $file['personal_data'] = []; } $pd = []; - if(trim($row['data subject'])) { + if (trim($row['data subject'])) { $pd['data_subject'] = $row['data subject']; } - if(trim($row['data categories'])) { - foreach(explode(", ", $row['data categories']) as $dc) { + if (trim($row['data categories'])) { + foreach (explode(", ", $row['data categories']) as $dc) { $dataCategory = []; $dataCategory['name'] = $dc; $pd['data_categories'][] = $dataCategory; } } - if(trim($row['description'])) { + if (trim($row['description'])) { $pd['description'] = $row['description']; } - if(trim($row['retention period']) != "") { + if (trim($row['retention period']) != "") { $pd['retention_period'] = $row['retention period']; } - if(trim($row['retention period unit'])) { + if (trim($row['retention period unit'])) { $pd['retention_period_mode'] = $row['retention period unit']; } - if(trim($row['retention period description'])) { + if (trim($row['retention period description'])) { $pd['retention_period_description'] = $row['retention period description']; } $file['personal_data'][] = $pd; } - if(trim($row['data recipient']) || trim($row['data recipient type']) || trim($row['description'])) { - if( !isset($file['recipients'])) { + if (trim($row['data recipient']) || trim($row['data recipient type']) || trim($row['description'])) { + if (!isset($file['recipients'])) { $file['recipients'] = []; } $r = []; - if(trim($row['data recipient'])) { + if (trim($row['data recipient'])) { $r['name'] = $row['data recipient']; } - if(trim($row['data recipient type'])) { + if (trim($row['data recipient type'])) { $r['type'] = $row['data recipient type']; } - if(trim($row['description'])) { + if (trim($row['description'])) { $r['description'] = $row['description']; } $file['recipients'][] = $r; } - if(trim($row['organisation of international transfer']) || trim($row['description']) || trim($row['country']) || trim($row['documents'])) { - if( !isset($file['international_transfers'])) { + if (trim($row['organisation of international transfer']) + || trim($row['description']) + || trim($row['country']) + || trim($row['documents']) + ) { + if (!isset($file['international_transfers'])) { $file['international_transfers'] = []; } $it = []; - if(trim($row['organisation of international transfer'])) + if (trim($row['organisation of international transfer'])) { $it['organisation'] = $row['organisation of international transfer']; - if(trim($row['description'])) + } + if (trim($row['description'])) { $it['description'] = $row['description']; - if(trim($row['country'])) + } + if (trim($row['country'])) { $it['country'] = $row['country']; - if(trim($row['documents'])) + } + if (trim($row['documents'])) { $it['documents'] = $row['documents']; + } $file['international_transfers'][] = $it; } - if(trim($row['data processor name'])) { - if( !isset($file['processors'])) { + if (trim($row['data processor name'])) { + if (!isset($file['processors'])) { $file['processors'] = []; } $p = []; $p['name'] = $row['data processor name']; - if(trim($row['data processor contact'])) + if (trim($row['data processor contact'])) { $p['contact'] = $row['data processor contact']; - if(trim($row['activities'])) + } + if (trim($row['activities'])) { $p['activities'] = $row['activities']; - if(trim($row['data processor security measures'])) + } + if (trim($row['data processor security measures'])) { $p['security_measures'] = $row['data processor security measures']; - if(trim($row['data processor representative name'])) { + } + if (trim($row['data processor representative name'])) { $rep = []; $rep['name'] = $row['data processor representative name']; - if(trim($row['data processor representative contact'])) + if (trim($row['data processor representative contact'])) { $rep['contact'] = $row['data processor representative contact']; + } $p['representative'] = $rep; } - if(trim($row['data processor data protection officer name'])) { + if (trim($row['data processor data protection officer name'])) { $dpo = []; $dpo['name'] = $row['data processor data protection officer name']; - if(trim($row['data processor data protection officer contact'])) + if (trim($row['data processor data protection officer contact'])) { $dpo['contact'] = $row['data processor data protection officer contact']; + } $p['data_protection_officer'] = $dpo; } $file['processors'][] = $p; } } - if ($file !== false && $file['name'] && ($id = $this->importFromArray($file, $anrId)) !== false) { + if (isset($file['name']) && ($id = $this->importFromArray($file, $anrId)) !== false) { $ids[] = $id; } else { - $errors[] = 'The file "' . $file['name'] . '" can\'t be imported'; + $errors[] = 'The file "' . ($file['name'] ?? '') . '" can\'t be imported'; } } + return [$ids, $errors]; } /** * Imports a record from a data array. This data is generally what has been exported into a file. + * * @param array $data The record's data fields - * @param Anr $anr The target ANR id + * @param int $anr The target ANR id + * * @return bool|int The ID of the generated asset, or false if an error occurred. */ public function importFromArray($data, $anr) @@ -539,8 +600,8 @@ public function importFromArray($data, $anr) $newData = []; $newData['anr'] = $anr; $newData['label'] = $data['name']; - $newData['purposes'] = (isset($data['purposes']) ? $data['purposes'] : ''); - $newData['secMeasures'] = (isset($data['security_measures']) ? $data['security_measures'] : ''); + $newData['purposes'] = $data['purposes'] ?? ''; + $newData['secMeasures'] = $data['security_measures'] ?? ''; if (isset($data['controller'])) { $newData['controller'] = $this->recordActorService->importFromArray($data['controller'], $anr); } @@ -584,7 +645,11 @@ public function importFromArray($data, $anr) } if (isset($data['international_transfers'])) { foreach ($data['international_transfers'] as $it) { - $internationalTransfers['id'] = $this->recordInternationalTransferService->importFromArray($it, $anr, $id); + $internationalTransfers['id'] = $this->recordInternationalTransferService->importFromArray( + $it, + $anr, + $id + ); $newData['internationalTransfers'][] = $internationalTransfers; } } diff --git a/src/Service/AnrRecordServiceFactory.php b/src/Service/AnrRecordServiceFactory.php index e821815e..1d191e73 100644 --- a/src/Service/AnrRecordServiceFactory.php +++ b/src/Service/AnrRecordServiceFactory.php @@ -8,6 +8,8 @@ namespace Monarc\FrontOffice\Service; use Monarc\Core\Service\AbstractServiceFactory; +use Monarc\FrontOffice\Table\AnrTable; +use Monarc\FrontOffice\Table\UserAnrTable; /** * Record Service Factory @@ -19,14 +21,14 @@ class AnrRecordServiceFactory extends AbstractServiceFactory { protected $ressources = [ 'table' => 'Monarc\FrontOffice\Model\Table\RecordTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Record', + 'entity' => 'Monarc\FrontOffice\Entity\Record', 'recordActorService' => 'Monarc\FrontOffice\Service\AnrRecordActorService', 'recordProcessorService' => 'Monarc\FrontOffice\Service\AnrRecordProcessorService', 'recordRecipientService' => 'Monarc\FrontOffice\Service\AnrRecordRecipientService', 'recordPersonalDataService' => 'Monarc\FrontOffice\Service\AnrRecordPersonalDataService', 'recordInternationalTransferService' => 'Monarc\FrontOffice\Service\AnrRecordInternationalTransferService', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', + 'userAnrTable' => UserAnrTable::class, + 'anrTable' => AnrTable::class, 'actorTable' => 'Monarc\FrontOffice\Model\Table\RecordActorTable', 'processorTable' => 'Monarc\FrontOffice\Model\Table\RecordProcessorTable', 'recipientTable' => 'Monarc\FrontOffice\Model\Table\RecordRecipientTable', diff --git a/src/Service/AnrReferentialService.php b/src/Service/AnrReferentialService.php index 5a66cd54..2947f576 100644 --- a/src/Service/AnrReferentialService.php +++ b/src/Service/AnrReferentialService.php @@ -1,57 +1,100 @@ -referentialTable->findByParams($params) as $referential) { + $result[] = $this->prepareReferentialDataResult($referential, true); + } + + return $result; + } + + public function getReferentialData(Anr $anr, string $uuid): array + { + /** @var Referential $referential */ + $referential = $this->referentialTable->findByUuidAndAnr($uuid, $anr); + + return $this->prepareReferentialDataResult($referential); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): Referential + { + /** @var Referential $referential */ + $referential = (new Referential())->setAnr($anr)->setLabels($data); + if (!empty($data['uuid'])) { + $referential->setUuid($data['uuid']); + } + + $this->referentialTable->save($referential, $saveInDb); + + return $referential; + } + + public function update(Anr $anr, string $uuid, array $data): Referential { - $data = $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - 1, - 0, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd - ); - - return array_slice($data, ($page - 1) * $limit, $limit, false); + /** @var Referential $referential */ + $referential = $this->referentialTable->findByUuidAndAnr($uuid, $anr); + + $referential->setLabels($data); + + $this->referentialTable->save($referential); + + return $referential; } - /** - * Fetches and returns the list of referentials from the common database. - * @param int $filter Keywords to search - * @return array An array of available referentials from the common database (knowledge base) - */ - public function getCommonReferentials($filter, $order) + public function delete(Anr $anr, string $uuid): void { + /** @var Referential $referential */ + $referential = $this->referentialTable->findByUuidAndAnr($uuid, $anr); - // Fetch the referentials from the common database - $selfCoreService = $this->get('selfCoreService'); - $referentials = $selfCoreService->getList(1, 25, $order, $filter, null); + $this->referentialTable->remove($referential); + } + + private function prepareReferentialDataResult(Referential $referential, bool $includeMeasuresRisks = false): array + { + $measures = []; + foreach ($referential->getMeasures() as $measure) { + $measuresData = array_merge( + ['uuid' => $measure->getUuid(), 'code' => $measure->getCode()], + $measure->getLabels() + ); + if ($includeMeasuresRisks) { + $measuresData['amvs'] = []; + $measuresData['rolfRisks'] = []; + foreach ($measure->getAmvs() as $amv) { + $measuresData['amvs'][] = [ + 'uuid' => $amv->getUuid(), + ]; + } + foreach ($measure->getRolfRisks() as $rolfRisk) { + $measuresData['rolfRisks'][] = [ + 'uuid' => $rolfRisk->getId(), + ]; + } + } + $measures[] = $measuresData; + } - return $referentials; + return array_merge(['uuid' => $referential->getUuid()], $referential->getLabels(), ['measures' => $measures]); } } diff --git a/src/Service/AnrReferentialServiceFactory.php b/src/Service/AnrReferentialServiceFactory.php deleted file mode 100644 index 7302fa30..00000000 --- a/src/Service/AnrReferentialServiceFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\ReferentialTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Referential', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'selfCoreService' => 'Monarc\Core\Service\ReferentialService', - ]; -} diff --git a/src/Service/AnrRolfRiskService.php b/src/Service/AnrRolfRiskService.php index ccebc1df..d526e08f 100755 --- a/src/Service/AnrRolfRiskService.php +++ b/src/Service/AnrRolfRiskService.php @@ -1,26 +1,261 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $formattedInputParams): array + { + $rolfRiskData = []; + /** @var Entity\RolfRisk $rolfRisk */ + foreach ($this->rolfRiskTable->findByParams($formattedInputParams) as $rolfRisk) { + $rolfRiskData[] = $this->prepareRolfRiskData($rolfRisk); + } + + return $rolfRiskData; + } + + public function getCount(FormattedInputParams $formattedInputParams): int + { + return $this->rolfRiskTable->countByParams($formattedInputParams); + } + + public function getRolfRiskData(Entity\Anr $anr, int $id): array + { + /** @var Entity\RolfRisk $rolfRisk */ + $rolfRisk = $this->rolfRiskTable->findByIdAndAnr($id, $anr); + + return $this->prepareRolfRiskData($rolfRisk); + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\RolfRisk + { + /** @var Entity\RolfRisk $rolfRisk */ + $rolfRisk = (new Entity\RolfRisk()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setCreator($this->connectedUser->getEmail()); + + if (!empty($data['measures'])) { + /** @var Entity\Measure $measure */ + foreach ($this->measureTable->findByUuidsAndAnr($data['measures'], $anr) as $measure) { + $rolfRisk->addMeasure($measure); + } + } + if (!empty($data['tags'])) { + /** @var Entity\RolfTag $rolfTag */ + foreach ($this->rolfTagTable->findByIdsAndAnr($data['tags'], $anr) as $rolfTag) { + $rolfRisk->addTag($rolfTag); + /* Create operation instance risks for the linked rolf tag. */ + /** @var Entity\MonarcObject $monarcObject */ + foreach ($rolfTag->getObjects() as $monarcObject) { + foreach ($monarcObject->getInstances() as $instance) { + $this->anrInstanceRiskOpService->createInstanceRiskOpWithScales( + $instance, + $monarcObject, + $rolfRisk + ); + } + } + } + } + + $this->rolfRiskTable->save($rolfRisk, $saveInDb); + + return $rolfRisk; + } + + public function createList(Entity\Anr $anr, array $data): array + { + $createdRowsNum = []; + foreach ($data as $rowNum => $rowData) { + $this->create($anr, $rowData, false); + $createdRowsNum[] = $rowNum; + } + $this->rolfRiskTable->flush(); + + return $createdRowsNum; + } + + public function update(Entity\Anr $anr, int $id, array $data): Entity\RolfRisk + { + /** @var Entity\RolfRisk $rolfRisk */ + $rolfRisk = $this->rolfRiskTable->findByIdAndAnr($id, $anr); + + $rolfRisk->removeAllMeasures(); + if (!empty($data['measures'])) { + /** @var Entity\Measure $measure */ + foreach ($this->measureTable->findByUuidsAndAnr($data['measures'], $anr) as $measure) { + $rolfRisk->addMeasure($measure); + } + } + + $rolfTagIds = array_map('\intval', $data['tags']); + foreach ($rolfRisk->getTags() as $rolfTag) { + $rolfTagIdKey = \array_search($rolfTag->getId(), $rolfTagIds, true); + if ($rolfTagIdKey !== false) { + unset($rolfTagIds[$rolfTagIdKey]); + } else { + $rolfRisk->removeTag($rolfTag); + /* Set the related operational risks to specific. */ + foreach ($rolfTag->getObjects() as $monarcObject) { + $instancesRisksOp = $this->instanceRiskOpTable->findByObjectAndRolfRisk($monarcObject, $rolfRisk); + foreach ($instancesRisksOp as $instanceRiskOp) { + $this->instanceRiskOpTable->save($instanceRiskOp->setIsSpecific(true), false); + } + } + } + } + if (!empty($rolfTagIds)) { + /** @var Entity\RolfTag $rolfTag */ + foreach ($this->rolfTagTable->findByIdsAndAnr($rolfTagIds, $anr) as $rolfTag) { + $rolfRisk->addTag($rolfTag); + /* Create operation instance risks for the linked rolf tag. */ + /** @var Entity\MonarcObject $monarcObject */ + foreach ($rolfTag->getObjects() as $monarcObject) { + foreach ($monarcObject->getInstances() as $instance) { + $this->anrInstanceRiskOpService->createInstanceRiskOpWithScales( + $instance, + $monarcObject, + $rolfRisk + ); + } + } + } + } + + if ($rolfRisk->areLabelsDifferent($data) || $rolfRisk->areDescriptionsDifferent($data)) { + $rolfRisk->setLabels($data)->setDescriptions($data); + /* If the labels or descriptions changed the operational risks labels have to be updated as well. */ + foreach ($rolfRisk->getTags() as $rolfTag) { + foreach ($rolfTag->getObjects() as $monarcObject) { + $instancesRisksOp = $this->instanceRiskOpTable->findByObjectAndRolfRisk($monarcObject, $rolfRisk); + foreach ($instancesRisksOp as $instanceRiskOp) { + $instanceRiskOp->setRiskCacheCode($rolfRisk->getCode()) + ->setRiskCacheLabels([ + 'riskCacheLabel1' => $rolfRisk->getLabel(1), + 'riskCacheLabel2' => $rolfRisk->getLabel(2), + 'riskCacheLabel3' => $rolfRisk->getLabel(3), + 'riskCacheLabel4' => $rolfRisk->getLabel(4), + ]) + ->setRiskCacheDescriptions([ + 'riskCacheDescription1' => $rolfRisk->getDescription(1), + 'riskCacheDescription2' => $rolfRisk->getDescription(2), + 'riskCacheDescription3' => $rolfRisk->getDescription(3), + 'riskCacheDescription4' => $rolfRisk->getDescription(4), + ]); + + $this->instanceRiskOpTable->save($instanceRiskOp, false); + } + } + } + } + + $this->rolfRiskTable->save($rolfRisk->setCode($data['code'])->setUpdater($this->connectedUser->getEmail())); + + return $rolfRisk; + } + + public function delete(Entity\Anr $anr, int $id): void + { + /** @var Entity\RolfRisk $rolfRisk */ + $rolfRisk = $this->rolfRiskTable->findByIdAndAnr($id, $anr); + $this->removeRolfRisk($anr, $rolfRisk); + } + + public function deleteList(Entity\Anr $anr, array $data): void + { + /** @var Entity\RolfRisk $rolfRisk */ + foreach ($this->rolfRiskTable->findByIdsAndAnr($data, $anr) as $rolfRisk) { + $this->removeRolfRisk($anr, $rolfRisk, false); + } + $this->rolfRiskTable->flush(); + } + + /** + * Performs the measures linking to the rolf risks when a new referential mapping is processed. + */ + public function linkMeasuresToRisks( + Entity\Anr $anr, + string $sourceReferentialUuid, + string $destinationReferentialUuid + ): void { + /** @var Entity\Referential $destinationReferential */ + $destinationReferential = $this->referentialTable->findByUuidAndAnr($destinationReferentialUuid, $anr); + foreach ($destinationReferential->getMeasures() as $destinationMeasure) { + foreach ($destinationMeasure->getLinkedMeasures() as $measureLink) { + if ($measureLink->getReferential()->getUuid() === $sourceReferentialUuid) { + foreach ($measureLink->getRolfRisks() as $rolfRisk) { + $destinationMeasure->addRolfRisk($rolfRisk); + } + $this->measureTable->save($destinationMeasure, false); + } + } + } + $this->measureTable->flush(); + } + + private function removeRolfRisk(Entity\Anr $anr, Entity\RolfRisk $rolfRisk, bool $saveInDb = true): void + { + foreach ($this->instanceRiskOpTable->findByAnrAndRolfRisk($anr, $rolfRisk) as $instanceRiskOp) { + $this->instanceRiskOpTable->save($instanceRiskOp->setIsSpecific(true), false); + } + + $this->rolfRiskTable->remove($rolfRisk, $saveInDb); + } + + private function prepareRolfRiskData(Entity\RolfRisk $rolfRisk): array + { + $tagsData = []; + foreach ($rolfRisk->getTags() as $tag) { + $tagsData[] = array_merge([ + 'id' => $tag->getId(), + 'code' => $tag->getCode(), + ], $tag->getLabels()); + } + $measuresData = []; + foreach ($rolfRisk->getMeasures() as $measure) { + $measuresData[] = array_merge([ + 'uuid' => $measure->getUuid(), + 'code' => $measure->getCode(), + 'referential' => [ + 'uuid' => $measure->getReferential()->getUuid(), + ], + ], $measure->getLabels()); + } + + return array_merge([ + 'id' => $rolfRisk->getId(), + 'code' => $rolfRisk->getCode(), + 'tags' => $tagsData, + 'measures' => $measuresData, + ], $rolfRisk->getLabels(), $rolfRisk->getDescriptions()); + } } diff --git a/src/Service/AnrRolfRiskServiceFactory.php b/src/Service/AnrRolfRiskServiceFactory.php deleted file mode 100755 index bb9c3a21..00000000 --- a/src/Service/AnrRolfRiskServiceFactory.php +++ /dev/null @@ -1,32 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\RolfRisk', - 'table' => 'Monarc\FrontOffice\Model\Table\RolfRiskTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'tagTable' => 'Monarc\FrontOffice\Model\Table\RolfTagTable', - 'rolfTagTable' => 'Monarc\FrontOffice\Model\Table\RolfTagTable', - 'MonarcObjectTable' => 'Monarc\FrontOffice\Model\Table\MonarcObjectTable', - 'instanceTable' => 'Monarc\FrontOffice\Model\Table\InstanceTable', - 'measureTable' => 'Monarc\FrontOffice\Model\Table\MeasureTable', - 'referentialTable' => 'Monarc\FrontOffice\Model\Table\ReferentialTable', - 'instanceRiskOpTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskOpTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'instanceRiskOpService' => 'Monarc\FrontOffice\Service\AnrInstanceRiskOpService', - ]; -} diff --git a/src/Service/AnrRolfTagService.php b/src/Service/AnrRolfTagService.php index 714ebed6..ebf51f8a 100755 --- a/src/Service/AnrRolfTagService.php +++ b/src/Service/AnrRolfTagService.php @@ -1,20 +1,107 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $formattedInputParams): array + { + $result = []; + /** @var RolfTag $rolfTag */ + foreach ($this->rolfTagTable->findByParams($formattedInputParams) as $rolfTag) { + $result[] = $this->prepareRolfTagData($rolfTag); + } + + return $result; + } + + public function getCount(FormattedInputParams $formattedInputParams): int + { + return $this->rolfTagTable->countByParams($formattedInputParams); + } + + public function getRolfTagData(Anr $anr, int $id): array + { + /** @var RolfTag $rolfTag */ + $rolfTag = $this->rolfTagTable->findByIdAndAnr($id, $anr); + + return $this->prepareRolfTagData($rolfTag); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): RolfTag + { + /** @var RolfTag $rolfTag */ + $rolfTag = (new RolfTag()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels($data) + ->setCreator($this->connectedUser->getEmail()); + + $this->rolfTagTable->save($rolfTag, $saveInDb); + + return $rolfTag; + } + + public function createList(Anr $anr, array $data): array + { + $createdRowsNumbers = []; + foreach ($data as $rowNum => $rowData) { + $this->create($anr, $rowData, false); + $createdRowsNumbers[] = $rowNum; + } + + return $createdRowsNumbers; + } + + public function update(Anr $anr, int $id, array $data): RolfTag + { + /** @var RolfTag $rolfTag */ + $rolfTag = $this->rolfTagTable->findByIdAndAnr($id, $anr); + + $rolfTag->setCode($data['code'])->setLabels($data)->setUpdater($this->connectedUser->getEmail()); + + $this->rolfTagTable->save($rolfTag); + + return $rolfTag; + } + + public function delete(Anr $anr, int $id): void + { + /** @var RolfTag $rolfTag */ + $rolfTag = $this->rolfTagTable->findByIdAndAnr($id, $anr); + + $this->rolfTagTable->remove($rolfTag); + } + + public function deleteList(Anr $anr, array $data): void + { + $this->rolfTagTable->removeList($this->rolfTagTable->findByIdsAndAnr($data, $anr)); + } + + private function prepareRolfTagData(RolfTag $rolfTag): array + { + return array_merge([ + 'id' => $rolfTag->getId(), + 'code' => $rolfTag->getCode(), + ], $rolfTag->getLabels()); + } } diff --git a/src/Service/AnrRolfTagServiceFactory.php b/src/Service/AnrRolfTagServiceFactory.php deleted file mode 100755 index 9043b768..00000000 --- a/src/Service/AnrRolfTagServiceFactory.php +++ /dev/null @@ -1,24 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\RolfTag', - 'table' => 'Monarc\FrontOffice\Model\Table\RolfTagTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - ]; -} diff --git a/src/Service/AnrScaleCommentService.php b/src/Service/AnrScaleCommentService.php index bf381ad3..380d0f92 100755 --- a/src/Service/AnrScaleCommentService.php +++ b/src/Service/AnrScaleCommentService.php @@ -1,59 +1,89 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $formattedInputParams): array { - $class = $this->get('entity'); - - /** @var ScaleComment $entity */ - $entity = new $class(); - $entity->setLanguage($this->getLanguage()); - $entity->setDbAdapter($this->get('table')->getDb()); - - // If a scale is set, ensure we retrieve the proper scale object - if (isset($data['scale'])) { - $scale = $this->get('scaleTable')->getEntity($data['scale']); - $entity->setScale($scale); - - // If this is not an IMPACT scale, remove the impact type as we won't need it - if ($scale->type != Scale::TYPE_IMPACT) { - unset($data['scaleImpactType']); - } + $result = []; + /** @var Entity\ScaleComment $scaleComment */ + foreach ($this->scaleCommentTable->findByParams($formattedInputParams) as $scaleComment) { + $result[] = array_merge([ + 'id' => $scaleComment->getId(), + 'scaleIndex' => $scaleComment->getScaleIndex(), + 'scaleValue' => $scaleComment->getScaleValue(), + 'scaleImpactType' => $scaleComment->getScaleImpactType() === null ? null : [ + 'id' => $scaleComment->getScaleImpactType()->getId(), + 'type' => $scaleComment->getScaleImpactType()->getType(), + ] + ], $scaleComment->getComments()); } - $entity->exchangeArray($data); - $dependencies = (property_exists($this, 'dependencies')) ? $this->dependencies : []; - $this->setDependencies($entity, $dependencies); + return $result; + } + + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\ScaleComment + { + /** @var Entity\Scale $scale */ + $scale = isset($data['scale']) && $data['scale'] instanceof Entity\Scale + ? $data['scale'] + : $this->scaleTable->findByIdAndAnr($data['scaleId'], $anr); + + ScaleCommentSuperClass::validateScaleIndexValue($scale, $data['scaleIndex']); + + /** @var Entity\ScaleComment $scaleComment */ + $scaleComment = (new Entity\ScaleComment()) + ->setAnr($anr) + ->setScale($scale) + ->setComments($data) + ->setScaleIndex($data['scaleIndex']) + ->setScaleValue($data['scaleValue']) + ->setCreator($this->connectedUser->getEmail()); + + if (!empty($data['scaleImpactType'])) { + /** @var Entity\ScaleImpactType $scaleImpactType */ + $scaleImpactType = $data['scaleImpactType'] instanceof Entity\ScaleImpactType + ? $data['scaleImpactType'] + : $this->scaleImpactTypeTable->findByIdAndAnr($data['scaleImpactType'], $anr); + $scaleComment->setScaleImpactType($scaleImpactType); + } + + $this->scaleCommentTable->save($scaleComment, $saveInDb); + + return $scaleComment; + } + + public function update(Entity\Anr $anr, int $id, array $data): Entity\ScaleComment + { + /** @var Entity\ScaleComment $scaleComment */ + $scaleComment = $this->scaleCommentTable->findByIdAndAnr($id, $anr); - /** @var AnrTable $table */ - $table = $this->get('table'); + $this->scaleCommentTable->save($scaleComment->setComments($data)->setUpdater($this->connectedUser->getEmail())); - return $table->save($entity, $last); + return $scaleComment; } } diff --git a/src/Service/AnrScaleCommentServiceFactory.php b/src/Service/AnrScaleCommentServiceFactory.php deleted file mode 100755 index 5b7bd830..00000000 --- a/src/Service/AnrScaleCommentServiceFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\ScaleComment', - 'table' => 'Monarc\FrontOffice\Model\Table\ScaleCommentTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'scaleTable' => 'Monarc\FrontOffice\Model\Table\ScaleTable', - 'scaleImpactTypeTable' => 'Monarc\FrontOffice\Model\Table\ScaleImpactTypeTable', - ]; -} diff --git a/src/Service/AnrScaleImpactTypeService.php b/src/Service/AnrScaleImpactTypeService.php new file mode 100755 index 00000000..b36abc37 --- /dev/null +++ b/src/Service/AnrScaleImpactTypeService.php @@ -0,0 +1,118 @@ +connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(Entity\Anr $anr): array + { + $result = []; + $scaleImpactTypesShortcuts = ScaleImpactTypeSuperClass::getScaleImpactTypesShortcuts(); + /** @var Entity\ScaleImpactType $scaleImpactType */ + foreach ($this->scaleImpactTypeTable->findByAnr($anr) as $scaleImpactType) { + $result[] = array_merge([ + 'id' => $scaleImpactType->getId(), + 'isHidden' => (int)$scaleImpactType->isHidden(), + 'isSys' => (int)$scaleImpactType->isSys(), + 'type' => $scaleImpactTypesShortcuts[$scaleImpactType->getType()] ?? 'CUS', + ], $scaleImpactType->getLabels()); + } + + return $result; + } + + public function create(Entity\Anr $anr, array $data, bool $saveInTheDb = true): Entity\ScaleImpactType + { + $scaleImpactType = (new Entity\ScaleImpactType()) + ->setAnr($anr) + ->setScale( + $data['scale'] instanceof Entity\Scale ? $data['scale'] : $this->scaleTable->findById($data['scale']) + ) + ->setLabels($data['labels'] ?? $data) + ->setType($data['type'] ?? $this->scaleImpactTypeTable->findMaxTypeValueByAnr($anr) + 1) + ->setCreator($this->connectedUser->getEmail()); + if (isset($data['isHidden'])) { + $scaleImpactType->setIsHidden((bool)$data['isHidden']); + } + + /* Create InstanceConsequence for each instance of the current anr. */ + /** @var Entity\Instance $instance */ + foreach ($this->instanceTable->findByAnr($scaleImpactType->getAnr()) as $instance) { + $this->instanceConsequenceService->createInstanceConsequence( + $instance, + $scaleImpactType, + $scaleImpactType->isHidden() + ); + } + + $this->scaleImpactTypeTable->save($scaleImpactType, $saveInTheDb); + + return $scaleImpactType; + } + + /** + * Hide/show or change label of scales impact types on the Evaluation scales page. + */ + public function patch(Entity\Anr $anr, int $id, array $data): Entity\ScaleImpactType + { + /** @var Entity\ScaleImpactType $scaleImpactType */ + $scaleImpactType = $this->scaleImpactTypeTable->findByIdAndAnr($id, $anr); + + if (isset($data['isHidden']) && (bool)$data['isHidden'] !== $scaleImpactType->isHidden()) { + /* It's not allowed to change visibility if analysis evaluation is started. */ + $this->anrScaleService->validateIfScalesAreEditable($anr); + + $scaleImpactType->setIsHidden((bool)$data['isHidden']); + $this->instanceConsequenceService->updateConsequencesByScaleImpactType( + $scaleImpactType, + (bool)$data['isHidden'] + ); + } + + $scaleImpactType->setLabels($data)->setUpdater($this->connectedUser->getEmail()); + + $this->scaleImpactTypeTable->save($scaleImpactType); + + return $scaleImpactType; + } + + + public function delete(Entity\Anr $anr, int $id): void + { + /* It's not allowed to delete the scale if analysis evaluation is started. */ + $this->anrScaleService->validateIfScalesAreEditable($anr); + + /** @var Entity\ScaleImpactType $scaleImpactType */ + $scaleImpactType = $this->scaleImpactTypeTable->findByIdAndAnr($id, $anr); + if ($scaleImpactType->isSys()) { + throw new Exception('Default Scale Impact Types can\'t be removed.', '403'); + } + + $this->scaleImpactTypeTable->remove($scaleImpactType); + } +} diff --git a/src/Service/AnrScaleService.php b/src/Service/AnrScaleService.php index 8e61ed57..d9d2f2f7 100755 --- a/src/Service/AnrScaleService.php +++ b/src/Service/AnrScaleService.php @@ -1,69 +1,96 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } - public function getList($page = 1, $limit = 25, $order = null, $filter = null, $filterAnd = null) + public function getList(Entity\Anr $anr): array { - $scales = parent::getList($page, $limit, $order, $filter, $filterAnd); - - /** @var AnrCheckStartedService $anrCheckStartedService */ - $anrCheckStartedService = $this->get('anrCheckStartedService'); + $result = []; + $availableTypes = CoreEntity\ScaleSuperClass::getAvailableTypes(); + /** @var Entity\Scale $scale */ + foreach ($this->scaleTable->findByAnr($anr) as $scale) { + $result[] = [ + 'id' => $scale->getId(), + 'type' => $availableTypes[$scale->getType()], + 'min' => $scale->getMin(), + 'max' => $scale->getMax(), + ]; + } - // Return both the scales, and also whether or not we can modify them - return [$scales, $anrCheckStartedService->canChange($filterAnd['anr'])]; + return $result; } - public function create($data, $last = true) + public function update(Entity\Anr $anr, int $id, array $data) { - $this->validateScaleEditable($data['anr']); + $this->validateIfScalesAreEditable($anr); - return parent::create($data,$last); - } + /** @var Entity\Scale $scale */ + $scale = $this->scaleTable->findByIdAndAnr($id, $anr); - public function patch($id, $data) - { - $this->validateScaleEditable($data['anr']); + $scale->setMin((int)$data['min']) + ->setMax((int)$data['max']) + ->setUpdater($this->connectedUser->getEmail()); - return parent::patch($id, $data); + $this->scaleTable->save($scale); + + return $scale; } - public function update($id, $data) + /** + * Returns whether the ANR sensitive values (scales values) can NOT be changed safely. + * It is not possible to change the scales thresholds when: + * - It has been explicitly disabled in the model ANR + * - Risks have been evaluated + * - Consequences have been evaluated + * - Threats have been evaluated + */ + public function areScalesNotEditable(Entity\Anr $anr): bool { - $this->validateScaleEditable($data['anr']); + $areScalesUpdatable = true; + if ($anr->getModelId() !== null) { + /** @var CoreEntity\Model $model */ + $model = $this->modelTable->findById($anr->getModelId()); + $areScalesUpdatable = $model->areScalesUpdatable(); + } - return parent::patch($id, $data); + return !$areScalesUpdatable + || $this->instanceRiskTable->isEvaluationStarted($anr) + || $this->instanceConsequenceTable->isEvaluationStarted($anr) + || $this->threatTable->isEvaluationStarted($anr) + || $this->operationalInstanceRiskScaleTable->isEvaluationStarted($anr); } - /** - * @throws Exception - */ - private function validateScaleEditable(int $anrId): void + public function validateIfScalesAreEditable(Entity\Anr $anr): void { - /** @var AnrCheckStartedService $anrCheckStartedService */ - $anrCheckStartedService = $this->get('anrCheckStartedService'); - if (!$anrCheckStartedService->canChange($anrId)) { - throw new Exception('Scale is not editable', 412); + if ($this->areScalesNotEditable($anr)) { + throw new Exception('Scales are not editable when the risks evaluation is started.', 412); } } } diff --git a/src/Service/AnrScaleServiceFactory.php b/src/Service/AnrScaleServiceFactory.php deleted file mode 100755 index 77e9e2e6..00000000 --- a/src/Service/AnrScaleServiceFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\ScaleTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Scale', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'anrCheckStartedService' => 'Monarc\FrontOffice\Service\AnrCheckStartedService', - 'scaleImpactTypeService' => 'Monarc\FrontOffice\Service\AnrScaleTypeService', - 'config' => 'Monarc\Core\Service\ConfigService', - ]; -} diff --git a/src/Service/AnrScaleTypeService.php b/src/Service/AnrScaleTypeService.php deleted file mode 100755 index ff2eb389..00000000 --- a/src/Service/AnrScaleTypeService.php +++ /dev/null @@ -1,128 +0,0 @@ - 'C', - 2 => 'I', - 3 => 'D', - 4 => 'R', - 5 => 'O', - 6 => 'L', - 7 => 'F', - 8 => 'P', - ]; - - /** - * Returns the types of scales available - * @return array [id => type kind string] - */ - public function getTypes() - { - return $this->types; - } - - /** - * @inheritdoc - */ - public function getList($page = 1, $limit = 25, $order = null, $filter = null, $filterAnd = null) - { - $types = $this->getTypes(); - - $scales = parent::getList($page, $limit, $order, $filter, $filterAnd); - - - foreach ($scales as $key => $scale) { - - if (isset($scale['type'])) { - if (isset($types[$scale['type']])) { - $scales[$key]['type'] = $types[$scale['type']]; - } else { - $scales[$key]['type'] = 'CUS'; // Custom user-defined column - } - $scales[$key]['type_id'] = $scale['type']; - } - } - - return $scales; - } - - /** - * @inheritdoc - */ - public function create($data, $last = true) - { - $scales = parent::getList(1,0, null, null, ['anr' => $data['anrId']]); - - if (!isset($data['isSys'])) { - $data['isSys'] = 0; - } - if (!isset($data['isHidden'])) { - $data['isSys'] = 0; - } - if (!isset($data['type'])) { - $data['type'] = count($scales) + 1; - } - - $anrId = $data['anr']; - - $class = $this->get('entity'); - - /** @var ScaleImpactType $entity */ - $entity = new $class(); - $entity->setDbAdapter($this->get('table')->getDb()); - - $entity->exchangeArray($data); - - $dependencies = (property_exists($this, 'dependencies')) ? $this->dependencies : []; - $this->setDependencies($entity, $dependencies); - - $entity->setLabels($data['labels']); - - $id = $this->get('table')->save($entity); - - // Retrieve all instances for the current ANR - /** @var InstanceTable $instanceTable */ - $instanceTable = $this->get('instanceTable'); - $instances = $instanceTable->getEntityByFields(['anr' => $anrId]); - $i = 1; - $nbInstances = count($instances); - foreach ($instances as $instance) { - //create instances consequences - $dataConsequences = [ - 'anr' => $anrId, - 'instance' => $instance->id, - 'object' => $instance->getObject()->getUuid(), - 'scaleImpactType' => $id, - ]; - /** @var InstanceConsequenceService $instanceConsequenceService */ - $instanceConsequenceService = $this->get('instanceConsequenceService'); - $instanceConsequenceService->create($dataConsequences, ($i == $nbInstances)); - $i++; - } - - return $id; - } -} diff --git a/src/Service/AnrScaleTypeServiceFactory.php b/src/Service/AnrScaleTypeServiceFactory.php deleted file mode 100755 index 568d7378..00000000 --- a/src/Service/AnrScaleTypeServiceFactory.php +++ /dev/null @@ -1,25 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\ScaleImpactTypeTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\ScaleImpactType', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'scaleTable' => 'Monarc\FrontOffice\Model\Table\ScaleTable', - 'instanceTable' => 'Monarc\FrontOffice\Model\Table\InstanceTable', - 'instanceConsequenceService' => 'Monarc\FrontOffice\Service\AnrInstanceConsequenceService' - ]; -} diff --git a/src/Service/AnrService.php b/src/Service/AnrService.php index 4f63e4a6..57b6f23b 100755 --- a/src/Service/AnrService.php +++ b/src/Service/AnrService.php @@ -1,2237 +1,1727 @@ -get('userCliTable'); - - /** @var UserSuperClass $connectedUser */ - $connectedUser = $userCliTable->getConnectedUser(); - - $isSuperAdmin = $connectedUser->hasRole(UserRole::SUPER_ADMIN_FO); + /** @var Entity\User $connectedUser */ + $connectedUser = $connectedUserService->getConnectedUser(); + $this->connectedUser = $connectedUser; + } - // Retrieve connected user anrs - $filterAnd['id'] = []; - if (!$isSuperAdmin) { - $anrs = $this->get('userAnrCliTable')->getEntityByFields(['user' => $connectedUser->getId()]); - foreach ($anrs as $a) { - $filterAnd['id'][$a->get('anr')->get('id')] = $a->get('anr')->get('id'); + public function getList(): array + { + /* For SUPER_ADMIN_FO all the analysis are fetched to be able to update the permissions. */ + $isSuperAdmin = $this->connectedUser->hasRole(Entity\UserRole::SUPER_ADMIN_FO); + + $anrData = []; + if ($isSuperAdmin) { + foreach ($this->anrTable->findAll() as $anr) { + if (!$anr->isAnrSnapshot()) { + $anrData[] = $this->getPreparedAnrData( + $anr, + $this->userAnrTable->findByAnrAndUser($anr, $this->connectedUser) + ); + } } } else { - $anrs = $this->anrCliTable->fetchAllObject(); - foreach ($anrs as $a) { - $filterAnd['id'][$a->get('id')] = $a->get('id'); + foreach ($this->connectedUser->getUserAnrs() as $userAnr) { + $anrData[] = $this->getPreparedAnrData($userAnr->getAnr(), $userAnr); } } - // Filter out snapshots, as we don't want to show them unless we explicitly ask for them - /** @var SnapshotTable $snapshotCliTable */ - $snapshotCliTable = $this->get('snapshotCliTable'); - $snapshots = $snapshotCliTable->getEntityByFields(['anr' => $filterAnd['id']]); - foreach ($snapshots as $snapshot) { - unset($filterAnd['id'][$snapshot->get('anr')->get('id')]); - } - - // Retrieve ANRs information - $anrs = $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd - ); + return $anrData; + } - /** @var User $user */ - $user = $userCliTable->findById($connectedUser->getId()); - foreach ($anrs as &$anr) { - //verify if this is the last current user's anr - $anr['isCurrentAnr'] = 0; - if ($user->getCurrentAnr() !== null && $anr['id'] === $user->getCurrentAnr()->getId()) { - $anr['isCurrentAnr'] = 1; - } + public function getAnrData(Entity\Anr $anr): array + { + $realAnrInUse = $anr; + if ($anr->isAnrSnapshot()) { + $realAnrInUse = $anr->getSnapshot()->getAnrReference(); + } + $userAnr = $this->userAnrTable->findByAnrAndUser($realAnrInUse, $this->connectedUser); - $lk = current($this->get('userAnrCliTable')->getEntityByFields([ - 'user' => $connectedUser->getId(), - 'anr' => $anr['id'], - ])); - $anr['rwd'] = (empty($lk)) ? -1 : $lk->get('rwd'); - - /* Check if the Anr is under background import. */ - $anr['importStatus'] = []; - if ($anr['status'] === AnrSuperClass::STATUS_UNDER_IMPORT) { - $importCronTask = $this->cronTaskService->getLatestTaskByNameWithParam( - CronTask::NAME_INSTANCE_IMPORT, - ['anrId' => $anr['id']] - ); - if ($importCronTask !== null && $importCronTask->getStatus() === CronTask::STATUS_IN_PROGRESS) { - $timeDiff = $importCronTask->getUpdatedAt()->diff(new DateTime()); - $instancesNumber = $this->instanceCliTable->countByAnrIdFromDate( - (int)$anr['id'], - $importCronTask->getUpdatedAt() - ); - $anr['importStatus'] = [ - 'executionTime' => $timeDiff->h . ' hours ' . $timeDiff->i . ' min ' . $timeDiff->s . ' sec', - 'createdInstances' => $instancesNumber, - ]; - } - } + if ($realAnrInUse->getId() !== $this->connectedUser->getCurrentAnr()?->getId()) { + $this->setCurrentAnrToConnectedUser($realAnrInUse, true); } - return $anrs; + return $this->getPreparedAnrData($anr, $userAnr, true); } /** - * @inheritdoc + * Creates a new analysis from a model that is in the common database. */ - public function getFilteredCount($filter = null, $filterAnd = null) + public function createBasedOnModel(array $data): Entity\Anr { - return count($this->getList(1, 0, null, $filter, $filterAnd)); - } + /** @var CoreEntity\Model $model */ + $model = $this->modelTable->findById((int)$data['model']); - /** - * Returns all ANRs without any filtering - * @return array An array of ANRs - */ - public function getAnrs() - { - return $this->get('anrCliTable')->fetchAll(); + $availableLanguages = $this->anrModelService->getAvailableLanguages($model->getId()); + if (empty($availableLanguages[$data['language']])) { + throw new Exception('Selected model\'s language is not supported', 412); + } + + return $this->duplicateAnr($model->getAnr(), $data); } /** - * @inheritdoc + * 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. */ - public function getEntity($id) - { - $anr = $this->get('table')->get($id); - - // Retrieve snapshot - /** @var SnapshotTable $snapshotCliTable */ - $snapshotCliTable = $this->get('snapshotCliTable'); - $anrSnapshot = current($snapshotCliTable->getEntityByFields(['anr' => $id])); - - $anr['isSnapshot'] = 0; - $anr['snapshotParent'] = null; - if (!empty($anrSnapshot)) { - // This is a snapshot, tag it as so - $anr['isSnapshot'] = 1; - $anr['rwd'] = 0; - $anr['snapshotParent'] = $anrSnapshot->get('anrReference')->get('id'); - } else { - /** @var UserTable $userCliTable */ - $userCliTable = $this->get('userCliTable'); - - /** @var CoreUser $connectedUser */ - $connectedUser = $userCliTable->getConnectedUser(); - - $lk = current($this->get('userAnrCliTable')->getEntityByFields([ - 'user' => $connectedUser->getId(), - 'anr' => $anr['id'], - ])); - if (empty($lk)) { - throw new Exception('Restricted ANR', 412); - } else { - $anr['rwd'] = $lk->get('rwd'); + public function duplicateAnr( + CoreEntity\AnrSuperClass $sourceAnr, + array $data = [], + bool $isSnapshotMode = false + ): Entity\Anr { + $isSourceCommon = $sourceAnr instanceof CoreEntity\Anr; + 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 + ) { + throw new Exception('You are not authorized to duplicate this analysis', 412); } } - $this->setUserCurrentAnr($id); + if ($isSourceCommon) { + /* Determine the language code when an analysis is created from a model. */ + $data['languageCode'] = strtolower($this->configService->getLanguageCodes()[$data['language']]); + } - return $anr; - } + $newAnr = Entity\Anr::constructFromObjectAndData($sourceAnr, $data) + ->setCreator($this->connectedUser->getEmail()); + if ($isSnapshotMode) { + /* The "[SNAP]" prefix is added for snapshots. */ + $newAnr->setLabel('[SNAP] ' . $newAnr->getLabel()); + } - /** - * Creates a new ANR from a model which is located inside the common database. - * @param array $data Data coming from the API - * @return Anr The newly created ANR id - * @throws Exception If the source model is not found - */ - public function createFromModelToClient($data): Anr - { - //retrieve model information - /** @var ModelTable $modelTable */ - $modelTable = $this->get('modelTable'); - $model = $modelTable->getEntity($data['model']); - unset($data['model']); + $this->anrTable->save($newAnr, false); - if ($model->get('status') != \Monarc\Core\Model\Entity\AbstractEntity::STATUS_ACTIVE) { // disabled or deleted - throw new Exception('Model not found', 412); + /* Not needed for snapshots creation or restoring. */ + if (!$isSnapshotMode) { + $userAnr = (new Entity\UserAnr()) + ->setUser($this->connectedUser) + ->setAnr($newAnr) + ->setRwd(Entity\UserAnr::FULL_PERMISSIONS_RWD) + ->setCreator($this->connectedUser->getEmail()); + + $this->userAnrTable->save($userAnr, false); } - return $this->duplicateAnr($model->anr, MonarcObject::SOURCE_COMMON, $model, $data); - } + /* Recreates assets */ + $assetsOldIdsToNewObjects = $this->duplicateAssets($sourceAnr, $newAnr, $isSourceCommon); + /* Recreates threats */ + $threatsOldIdsToNewObjects = $this->duplicateThreats($sourceAnr, $newAnr, $isSourceCommon); + /* Recreates vulnerabilities */ + $vulnerabilitiesOldIdsToNewObjects = $this->duplicateVulnerabilities($sourceAnr, $newAnr, $isSourceCommon); + + /* Recreates Referential, SoaCategories, Measures and links from an existing anr, a snapshot or core. */ + $referentialsUuidsToCreate = !empty($data['referentials']) ? array_column($data['referentials'], 'uuid') : []; + if ($sourceAnr instanceof Entity\Anr) { + foreach ($sourceAnr->getReferentials() as $referential) { + $referentialsUuidsToCreate[] = $referential->getUuid(); + } + } + $createdMeasuresUuidsToObjects = []; + if (!empty($referentialsUuidsToCreate)) { + $createdMeasuresUuidsToObjects = $this->updateReferentialsFromSource( + $newAnr, + $sourceAnr instanceof Entity\Anr ? $sourceAnr : null, + $referentialsUuidsToCreate, + false + ); + } - /** - * Add or remove referentials to/from an existing ANR. - * @param array $data Data coming from the API - * @return int - */ - public function updateReferentials($data) - { - // TODO: the goal is to remove such cases. Temporary unlimited. - // This may take a lot of time on huge referential. - ini_set('max_execution_time', 0); - - $anrTable = $this->get('anrCliTable'); - $anr = $anrTable->getEntity($data['id']); - $uuidArray = array_map( - function ($referential) { - return $referential['uuid']; - }, - $data['referentials'] + /* Recreate AMVs. */ + $amvsOldIdsToNewObjects = $this->duplicateAmvs( + $sourceAnr, + $newAnr, + $isSourceCommon, + $assetsOldIdsToNewObjects, + $threatsOldIdsToNewObjects, + $vulnerabilitiesOldIdsToNewObjects, + $createdMeasuresUuidsToObjects ); - // search for referentials to unlink from the anr - foreach ($anr->getReferentials() as $referential) { - if (!in_array($referential->getUuid(), $uuidArray, true)) { - $this->get('referentialCliTable')->delete([ - 'anr' => $anr->id, - 'uuid' => $referential->getUuid() - ]); - } - } + /* Recreate rolf tags and risks. */ + $rolfTagsOldIdsToNewObjects = $this->duplicateRolfTags($sourceAnr, $newAnr); + $rolfRisksOldIdsToNewObjects = $this + ->duplicateRolfRisks($sourceAnr, $newAnr, $rolfTagsOldIdsToNewObjects, $createdMeasuresUuidsToObjects); - // link new referentials to an ANR - foreach ($uuidArray as $uuid) { - // check if referential already linked to the anr - $referentials = $this->get('referentialCliTable')->getEntityByFields([ - 'anr' => $anr->id, - 'uuid' => $uuid - ]); - if (! empty($referentials)) { - // if referential already linked to the anr, go to next iteration - continue; - } + /* Recreate SOAs */ + $this->duplicateSoasAndSoaScaleComments($sourceAnr, $newAnr, $createdMeasuresUuidsToObjects, $isSourceCommon); - $referential = $this->get('referentialTable')->getEntity($uuid); - $measures = $referential->getMeasures(); - $referential->setMeasures(null); - - // duplicate the referential - $newReferential = new Referential($referential); - $newReferential->setAnr($anr); - - // duplicate categories - $categoryNewIds = []; - $category = $this->get('soaCategoryTable')->getEntityByFields(['referential' => $referential->getUuid()]); - foreach ($category as $cat) { - $newCategory = new SoaCategory($cat); - $newCategory->set('id', null); - $newCategory->setAnr($anr); - $newCategory->setMeasures(null); - $newCategory->setReferential($newReferential); - $categoryNewIds[$cat->id] = $newCategory; - } - $newReferential->setCategories($categoryNewIds); + /* Recreate Monarc objects and categories. */ + $monarcObjectsOldIdsToNewObjects = $this->duplicateObjectsAndCategories( + $sourceAnr, + $newAnr, + $assetsOldIdsToNewObjects, + $rolfTagsOldIdsToNewObjects, + $isSourceCommon + ); - // duplicate the measures - $measuresNewIds = []; - foreach ($measures as $measure) { - // duplicate and link the measures to the current referential - $newMeasure = (new Measure($measure)) - ->setAnr($anr) - ->setReferential($newReferential) - ->setCategory($categoryNewIds[$measure->category->id]); - foreach ($newMeasure->getMeasuresLinked() as $measureLinked) { - $data = []; - if (!count($this->get('measureMeasureCliTable')->getEntityByFields([ - 'anr' => $anr->id, - 'father' => $measure->getUuid(), - 'child' => $measureLinked->getUuid() - ]))) { - $data['father'] = $newMeasure->getUuid(); - $data['child'] = $measureLinked->getUuid(); - $newMeasureMeasure = new MeasureMeasure($data); - $newMeasureMeasure->setAnr($anr); - $this->get('measureMeasureCliTable')->save($newMeasureMeasure, false); - } + /* Recreate AnrInstanceMetadataFields */ + $anrInstanceMetadataFieldOldIdsToNewObjects = $this + ->duplicateAnrMetadataInstanceFields($sourceAnr, $newAnr, $isSourceCommon); - if (!count($this->get('measureMeasureCliTable')->getEntityByFields([ - 'anr' => $anr->id, - 'father' => $measureLinked->getUuid(), - 'child' => $newMeasure->getUuid() - ]))) { - $data['father'] = $measureLinked->getUuid(); - $data['child'] = $newMeasure->getUuid(); - $newMeasureMeasure = new MeasureMeasure($data); - $newMeasureMeasure->setAnr($anr); - $this->get('measureMeasureCliTable')->save($newMeasureMeasure, false); - } - } - $newMeasure->setMeasuresLinked(new ArrayCollection()); - $amvs = $newMeasure->getAmvs(); - $rolfRisks = $newMeasure->getRolfRisks(); - $newMeasure->amvs = new ArrayCollection; - $newMeasure->rolfRisks = new ArrayCollection; - // update the amv with the new measures from the current referential - foreach ($amvs as $amvCommon) { - // match the AMVs from common with AMVS from cli - $amvCli = $this->get('amvCliTable') - ->getEntityByFields([ - 'asset' => ['uuid' => $amvCommon->getAsset()->getUuid(), 'anr' => $anr->getId()], - 'threat' => ['uuid' => $amvCommon->getThreat()->getUuid(), 'anr' => $anr->getId()], - 'vulnerability' => [ - 'uuid' => $amvCommon->getVulnerability()->getUuid(), - 'anr' => $anr->id - ] - ]); - if (count($amvCli)) { - $newMeasure->addAmv($amvCli[0]); - } - } - foreach ($rolfRisks as $rolfRisk_common) { - // match the risks from common with risks from cli - $risk_cli = $this->get('rolfRiskCliTable')->getEntityByFields([ - 'anr' => $anr->id, - 'label' . $this->getLanguage() => $rolfRisk_common->getLabel($this->getLanguage()), - 'code' => $rolfRisk_common->getCode() - ]); - if (count($risk_cli)) { - //$risk_cli = $risk_cli[0]; - $newMeasure->addOpRisk($risk_cli[0]); - } - } - $measuresNewIds[] = $newMeasure; + /* Recreate Instances, InstanceRisks, InstanceConsequences and InstanceMetadata. */ + $this->duplicateInstancesTreeRisksSequencesRecommendationsMetadataAndScales( + $sourceAnr, + $newAnr, + $amvsOldIdsToNewObjects, + $assetsOldIdsToNewObjects, + $threatsOldIdsToNewObjects, + $vulnerabilitiesOldIdsToNewObjects, + $monarcObjectsOldIdsToNewObjects, + $anrInstanceMetadataFieldOldIdsToNewObjects, + $rolfRisksOldIdsToNewObjects, + $isSourceCommon + ); - $newSoa = new Soa(); - $newSoa->set('id', null); - $newSoa->setAnr($anr); - $newSoa->setMeasure($newMeasure); - $this->get('soaTable')->save($newSoa, false); - } - $newReferential->setMeasures($measuresNewIds); + /* Recreate questions & choices. */ + $this->duplicateQuestions($sourceAnr, $newAnr, $isSourceCommon); - $this->get('referentialCliTable')->save($newReferential); + if (!$isSourceCommon) { + /* Recreate interviews. */ + $this->duplicateInterviews($sourceAnr, $newAnr); + + /* Recreate all the ROPA's related entities. */ + $this->duplicateRopa($sourceAnr, $newAnr); } - return $anr->id; + if (!$isSnapshotMode) { + $this->setCurrentAnrToConnectedUser($newAnr); + } + + $this->anrTable->save($newAnr); + + return $newAnr; } - /** - * Duplicates either an existing ANR from the client, or an ANR model from the common database. - * @param int|AnrSuperClass $anr The ANR to clone, either its ID or the object - * @param string $source The source, either MonarcObject::SOURCE_CLIENT or MonarcObject::SOURCE_COMMON - * @param Model|null $model The source common model, or null if none - * @return Anr The newly created ANR - * @throws Exception - */ - public function duplicateAnr( - $anr, - $source = MonarcObject::SOURCE_CLIENT, - $model = null, - $data = [], - $isSnapshot = false, - $isSnapshotCloning = false - ): Anr { - // TODO: the goal is to remove such cases. Temporary unlimited. - // This may take a lot of time on huge ANRs. - ini_set('max_execution_time', 0); - - if (is_int($anr)) { - /** @var AnrTable $anrTable */ - $anrTable = $source === MonarcObject::SOURCE_COMMON ? $this->get('anrTable') : $this->get('anrCliTable'); - $anr = $anrTable->getEntity($anr); - } - - if (!$anr instanceof AnrSuperClass) { - throw new Exception('Anr missing', 412); - } - if (empty($model)) { - $idModel = $anr->get('model'); - } else { - $idModel = $model->get('id'); + public function patch(Entity\Anr $anr, array $data): Entity\Anr + { + /* Steps checkboxes setup. */ + if (isset($data['initAnrContext'])) { + $anr->setInitAnrContext($data['initAnrContext']); + } + if (isset($data['initEvalContext'])) { + $anr->setInitEvalContext($data['initEvalContext']); + } + if (isset($data['initRiskContext'])) { + $anr->setInitRiskContext($data['initRiskContext']); + } + if (isset($data['initDefContext'])) { + $anr->setInitDefContext($data['initDefContext']); + } + if (isset($data['modelImpacts'])) { + $anr->setModelImpacts($data['modelImpacts']); + } + if (isset($data['modelSummary'])) { + $anr->setModelSummary($data['modelSummary']); + } + if (isset($data['evalRisks'])) { + $anr->setEvalRisks($data['evalRisks']); + } + if (isset($data['evalPlanRisks'])) { + $anr->setEvalPlanRisks($data['evalPlanRisks']); + } + if (isset($data['manageRisks'])) { + $anr->setManageRisks($data['manageRisks']); + } + /* Context establishment texts. */ + if (isset($data['contextAnaRisk'])) { + $anr->setContextAnaRisk($data['contextAnaRisk']); + } + if (isset($data['synthThreat'])) { + $anr->setSynthThreat($data['synthThreat']); + } + if (isset($data['contextGestRisk'])) { + $anr->setContextGestRisk($data['contextGestRisk']); + } + if (isset($data['synthAct'])) { + $anr->setSynthAct($data['synthAct']); + } + /* Label, description update */ + if (isset($data['label']) && $anr->getLabel() !== $data['label']) { + $anr->setLabel($data['label']); + } + if (isset($data['description']) && $anr->getDescription() !== $data['description']) { + $anr->setDescription($data['description']); + } + /* Update the thresholds. */ + if (isset($data['seuil1']) && $anr->getSeuil1() !== $data['seuil1']) { + $anr->setSeuil1($data['seuil1']); + } + if (isset($data['seuil2']) && $anr->getSeuil2() !== $data['seuil2']) { + $anr->setSeuil2($data['seuil2']); + } + if (isset($data['seuilRolf1']) && $anr->getSeuilRolf1() !== $data['seuilRolf1']) { + $anr->setSeuilRolf1($data['seuilRolf1']); + } + if (isset($data['seuilRolf2']) && $anr->getSeuilRolf2() !== $data['seuilRolf2']) { + $anr->setSeuilRolf2($data['seuilRolf2']); } - if (!empty($idModel)) { - if (!$this->verifyLanguage($idModel)) { - throw new Exception('Error during analysis creation', 412); - } - } // if empty($idModel), maybe created from migration tool & model don't match with existing datas + if (isset($data['referentials'])) { + $this->updateReferentialsFromSource($anr, null, array_column($data['referentials'], 'uuid')); + } - /** @var UserTable $userCliTable */ - $userCliTable = $this->get('userCliTable'); + $anr->setUpdater($this->connectedUser->getEmail()); - /** @var CoreUser $connectedUser */ - $connectedUser = $userCliTable->getConnectedUser(); + $this->anrTable->save($anr); + + return $anr; + } - if ($source === MonarcObject::SOURCE_CLIENT - && !$isSnapshotCloning - && !$connectedUser->hasRole(UserRoleSuperClass::USER_ROLE_SYSTEM) - ) { - /** @var UserAnrTable $userAnrCliTable */ - $userAnrCliTable = $this->get('userAnrCliTable'); - $userAnr = $userAnrCliTable->findByAnrAndUser($anr, $connectedUser); - if ($userAnr === null) { - throw new Exception('You are not authorized to duplicate this analysis', 412); - } - } + public function delete(Entity\Anr $anr): void + { + /* Try to drop the stats. */ try { - // duplicate anr - $newAnr = new Anr($anr); - $newAnr->setId(null); - $newAnr->generateAndSetUuid(); - $newAnr->setObjects(new ArrayCollection()); - $newAnr->exchangeArray($data); - $newAnr->set('model', $idModel); - $newAnr->setReferentials(null); - $newAnr->setStatus(AnrSuperClass::STATUS_ACTIVE); - $newAnr->setCreator($connectedUser->getFirstname() . ' ' . $connectedUser->getLastname()); - if (!empty($model) && is_object($model)) { - $newAnr->set('cacheModelShowRolfBrut', $model->showRolfBrut); - $newAnr->set('cacheModelIsScalesUpdatable', $model->isScalesUpdatable); - } - if ($isSnapshot) { // if snapshot, add the prefix "[SNAP]" - for ($i = 1; $i <= 4; $i++) { - $lab = trim($newAnr->get('label' . $i)); - if (!empty($lab)) { - $newAnr->set('label' . $i, '[SNAP] ' . $lab); - } - } - } + $this->statsAnrService->deleteStatsForAnr($anr->getUuid()); + } catch (Throwable) { + } - /** @var AnrTable $anrCliTable */ - $anrCliTable = $this->get('anrCliTable'); - $anrCliTable->saveEntity($newAnr); + $this->anrTable->remove($anr); + } - // useless if the user is doing a snapshot or is restoring a snapshot (SnapshotService::restore) - if (!$isSnapshot && !$isSnapshotCloning) { - //add user to anr - $user = $userCliTable->findById($connectedUser->getId()); - $userAnr = (new UserAnr()) - ->setUser($user) - ->setAnr($newAnr) - ->setRwd(1) - ->setCreator($connectedUser->getFirstname() . ' ' . $connectedUser->getLastname()); - /** @var UserAnrTable $userAnrCliTable */ - $userAnrCliTable = $this->get('userAnrCliTable'); - $userAnrCliTable->saveEntity($userAnr, false); - } + private function getPreparedAnrData( + Entity\Anr $anr, + ?Entity\UserAnr $userAnr, + bool $includeSnapshotDetails = false + ): array { + $referentialData = []; + foreach ($anr->getReferentials() as $referential) { + $referentialData[] = [ + 'uuid' => $referential->getUuid(), + 'label' . $anr->getLanguage() => $referential->getLabel($anr->getLanguage()), + ]; + } - // duplicate themes - $themesNewIds = []; - $themes = $source === MonarcObject::SOURCE_COMMON - ? $this->get('themeTable')->fetchAllObject() - : $this->get('themeCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($themes as $theme) { - $newTheme = new Theme($theme); - $newTheme->set('id', null); - $newTheme->setAnr($newAnr); - $this->get('themeCliTable')->save($newTheme, false); - $themesNewIds[$theme->id] = $newTheme; - } + $anrData = [ + 'id' => $anr->getId(), + 'uuid' => $anr->getUuid(), + 'label' => $anr->getLabel(), + 'description' => $anr->getDescription(), + 'rwd' => $userAnr === null ? -1 : $userAnr->getRwd(), + 'referentials' => $referentialData, + 'isCurrentAnr' => (int)($this->connectedUser->getCurrentAnr() !== null + && $this->connectedUser->getCurrentAnr()->getId() === $anr->getId()), + 'status' => $anr->getStatus(), + 'creator' => $anr->getCreator(), + 'createdAt' => $anr->getCreatedAt()->format('d/m/Y H:i'), + 'language' => $anr->getLanguage(), + 'languageCode' => $anr->getLanguageCode(), + 'cacheModelAreScalesUpdatable' => (int)$anr->getCacheModelAreScalesUpdatable(), + 'cacheModelShowRolfBrut' => (int)$anr->getCacheModelShowRolfBrut(), + 'contextAnaRisk' => $anr->getContextAnaRisk(), + 'contextGestRisk' => $anr->getContextGestRisk(), + 'evalLivrableDone' => $anr->getEvalLivrableDone(), + 'evalPlanRisks' => $anr->getEvalPlanRisks(), + 'evalRisks' => $anr->getEvalRisks(), + 'initAnrContext' => $anr->getInitAnrContext(), + 'initDefContext' => $anr->getInitDefContext(), + 'initEvalContext' => $anr->getInitEvalContext(), + 'initLivrableDone' => $anr->getInitLivrableDone(), + 'initRiskContext' => $anr->getInitRiskContext(), + 'isSnapshot' => (int)$anr->isAnrSnapshot(), + 'isStatsCollected' => (int)$anr->isStatsCollected(), + 'isVisibleOnDashboard' => $anr->isVisibleOnDashboard(), + 'manageRisks' => $anr->getManageRisks(), + 'model' => $anr->getModelId(), + 'modelImpacts' => $anr->getModelImpacts(), + 'modelLivrableDone' => $anr->getModelLivrableDone(), + 'modelSummary' => $anr->getModelSummary(), + 'seuil1' => $anr->getSeuil1(), + 'seuil2' => $anr->getSeuil2(), + 'seuilRolf1' => $anr->getSeuilRolf1(), + 'seuilRolf2' => $anr->getSeuilRolf2(), + 'showRolfBrut' => (int)$anr->showRolfBrut(), + 'seuilTraitement' => $anr->getSeuilTraitement(), + 'synthAct' => $anr->getSynthAct(), + 'synthThreat' => $anr->getSynthThreat(), + ]; - // duplicate assets - $assetsNewIds = []; - if ($source == MonarcObject::SOURCE_COMMON) { - $assets1 = []; - if (!$model->isRegulator) { - $assets1 = $this->get('assetTable')->getEntityByFields(['mode' => Asset::MODE_GENERIC]); - } - $assets2 = []; - if (!$model->isGeneric) { - // $assets2 = $this->get('assetTable')->getEntityByFields(['mode' => Asset::MODE_SPECIFIC]); - // We fetch all the assets related to the specific model and linked to its configured anr. - $assets2 = array_merge( - $model->get('assets')->toArray(), - $this->get('assetTable')->findByAnr($model->getAnr()) - ); - } - $assets = array_merge($assets1, $assets2); - } else { - $assets = $this->get('assetCliTable')->getEntityByFields(['anr' => $anr->id]); + /* Check if the Anr is under background import. */ + $anrData['importStatus'] = []; + if ($anr->getStatus() === CoreEntity\AnrSuperClass::STATUS_UNDER_IMPORT) { + $importCronTask = $this->cronTaskService->getLatestTaskByNameWithParam( + Entity\CronTask::NAME_INSTANCE_IMPORT, + ['anrId' => $anr->getId()] + ); + if ($importCronTask !== null && $importCronTask->getStatus() === Entity\CronTask::STATUS_IN_PROGRESS) { + $timeDiff = $importCronTask->getUpdatedAt() !== null + ? $importCronTask->getUpdatedAt()->diff(new DateTime()) + : $importCronTask->getCreatedAt()->diff(new DateTime()); + $instancesNumber = $this->instanceTable->countByAnrIdFromDate( + $anr->getId(), + $importCronTask->getUpdatedAt() ?? $importCronTask->getCreatedAt() + ); + $anrData['importStatus'] = [ + 'executionTime' => $timeDiff->h . ' hours ' . $timeDiff->i . ' min ' . $timeDiff->s . ' sec', + 'createdInstances' => $instancesNumber, + ]; } - foreach ($assets as $asset) { - $newAsset = new Asset($asset); - $newAsset->setAnr($newAnr); - $newAsset->setMode(0); // force to generic - $this->get('assetCliTable')->save($newAsset, false); - $assetsNewIds[$asset->getUuid()] = $newAsset; + } + + if ($includeSnapshotDetails) { + $anrData['isSnapshot'] = (int)$anr->isAnrSnapshot(); + $anrData['snapshotParent'] = $anr->isAnrSnapshot() + ? $anr->getSnapshot()?->getAnrReference()->getId() + : null; + if ($anr->isAnrSnapshot()) { + $anrData['rwd'] = 0; } + } - // duplicate threats - $threatsNewIds = []; - if ($source === MonarcObject::SOURCE_COMMON) { - $threats = []; - if (!$model->isRegulator) { - $threats = $this->get('threatTable')->getEntityByFields(['mode' => Threat::MODE_GENERIC]); - } - if (!$model->isGeneric) { - // $threats2 = $this->get('threatTable')->getEntityByFields(['mode' => Threat::MODE_SPECIFIC]); - // We fetch all the threats related to the specific model and linked to its configured anr. - $threats2 = array_merge( - $model->get('threats')->toArray(), - $this->get('threatTable')->findByAnr($model->getAnr()) - ); - foreach ($threats2 as $t) { - $threats[] = $t; - } - unset($threats2); - } + return $anrData; + } + + /** + * @param string[] $referentialUuids + * + * @return Entity\Measure[] Returns list of created measures with uuids as keys ['UUID' => Measure]. + */ + private function updateReferentialsFromSource( + Entity\Anr $anr, + ?Entity\Anr $sourceAnr, + array $referentialUuids, + bool $recreateAmvRolfRiskAndSoaLinks = true + ): array { + $linkedReferentialUuids = []; + /* Removes already linked referentials from the list and unlink if not presented. */ + foreach ($anr->getReferentials() as $referential) { + $foundUuidKey = array_search($referential->getUuid(), $referentialUuids, true); + if ($foundUuidKey !== false) { + unset($referentialUuids[$foundUuidKey]); + $linkedReferentialUuids[] = $referential->getUuid(); } else { - $threats = $this->get('threatCliTable')->getEntityByFields(['anr' => $anr->id]); - } - foreach ($threats as $threat) { - $newThreat = new Threat($threat); - $newThreat->setAnr($newAnr); - if ($threat->theme) { - $newThreat->setTheme($themesNewIds[$threat->theme->id]); - } - $newThreat->setMode(0); // force to generic - $this->get('threatCliTable')->save($newThreat, false); - $threatsNewIds[$threat->getUuid()] = $newThreat; + /* The operation of removal is not supported in the UI. */ + $anr->removeReferential($referential); + $this->referentialTable->remove($referential, false); } + } - // duplicate vulnerabilities - $vulnerabilitiesNewIds = []; - if ($source === MonarcObject::SOURCE_COMMON) { - $vulnerabilities1 = []; - if (!$model->isRegulator) { - $vulnerabilities1 = $this->get('vulnerabilityTable') - ->getEntityByFields(['mode' => Vulnerability::MODE_GENERIC]); - } - $vulnerabilities2 = []; - if (!$model->isGeneric) { - //$vulnerabilities2 = $this->get('vulnerabilityTable') - // ->getEntityByFields(['mode' => Vulnerability::MODE_SPECIFIC]); - // We fetch all the vulns related to the specific model and linked to its configured anr. - $vulnerabilities2 = array_merge( - $model->get('vulnerabilities')->toArray(), - $this->get('vulnerabilityTable')->findByAnr($model->getAnr()) - ); - } - $vulnerabilities = array_merge($vulnerabilities1, $vulnerabilities2); + $createdMeasuresUuidsToObjects = []; + /* Links new referential to the analysis from core or the source anr. */ + foreach ($referentialUuids as $referentialUuid) { + if ($sourceAnr === null) { + $referentialFromSource = $this->coreReferentialTable->findByUuid($referentialUuid); } else { - $vulnerabilities = $this->get('vulnerabilityCliTable')->getEntityByFields(['anr' => $anr->id]); - } - foreach ($vulnerabilities as $vulnerability) { - $newVulnerability = new Vulnerability($vulnerability); - $newVulnerability->setAnr($newAnr); - $newVulnerability->setMode(0); // force to generic - $this->get('vulnerabilityCliTable')->save($newVulnerability, false); - $vulnerabilitiesNewIds[$vulnerability->getUuid()] = $newVulnerability; + $referentialFromSource = $this->referentialTable->findByUuidAndAnr($referentialUuid, $sourceAnr); } - // duplicate categories, referentials and measures - $measuresNewIds = []; - if ($source == MonarcObject::SOURCE_COMMON) { - foreach ($data['referentials'] as $referential_array) { - $referential = $this->get('referentialTable')->getEntity($referential_array['uuid']); - $measures = $referential->getMeasures(); - $referential->setMeasures(null); - - // duplicate the referential - $newReferential = new Referential($referential); - $newReferential->setAnr($newAnr); - - // duplicate categories - $categoryNewIds = []; - $category = $this->get('soaCategoryTable') - ->getEntityByFields(['referential' => $referential->getUuid()]); - foreach ($category as $cat) { - $newCategory = new SoaCategory($cat); - $newCategory->set('id', null); - $newCategory->setAnr($newAnr); - $newCategory->setMeasures(null); - $newCategory->setReferential($newReferential); - $categoryNewIds[$cat->id] = $newCategory; - } - $newReferential->setCategories($categoryNewIds); - - foreach ($measures as $measure) { - // duplicate and link the measures to the current referential - $newMeasure = (new Measure($measure)) - ->setAnr($newAnr) - ->setAmvs(new ArrayCollection()) - ->setRolfRisks(new ArrayCollection()) - ->setMeasuresLinked(new ArrayCollection()) - ->setReferential($newReferential) - ->setCategory($categoryNewIds[$measure->category->id]); - foreach ($measure->getMeasuresLinked() as $measureLinked) { - $newMeasureMeasure = (new MeasureMeasure([ - 'father' => $measure->getUuid(), - 'child' => $measureLinked->getUuid(), - ]))->setAnr($newAnr); - $this->get('measureMeasureCliTable')->save($newMeasureMeasure, false); - } - $measuresNewIds[$measure->getUuid()] = $newMeasure; - } - //$newReferential->setMeasures(null); - $this->get('referentialCliTable')->save($newReferential, false); - $this->get('referentialCliTable')->getDb()->flush(); - } - } else { // copy from an existing anr (or a snapshot) - $referentialTable = $this->get('referentialCliTable'); - $referentials = $referentialTable->getEntityByFields(['anr' => $anr->id]); - foreach ($referentials as $referential) { - // duplicate referentials - $measures = $referential->getMeasures(); - $categories = $referential->getCategories(); - $referential->setMeasures(null); - $referential->setCategories(null); - $newReferential = new Referential($referential); - $newReferential->setAnr($newAnr); - - $categoryNewIds = []; - foreach ($categories as $cat) { - $newCategory = new SoaCategory($cat); - $newCategory->set('id', null); - $newCategory->setAnr($newAnr); - $newCategory->setMeasures(null); - $newCategory->setReferential($newReferential); - $categoryNewIds[$cat->id] = $newCategory; - } - $newReferential->setCategories($categoryNewIds); - - $newMeasures = []; - foreach ($measures as $measure) { - // duplicate and link the measures to the current referential - $newMeasure = (new Measure($measure)) - ->setAnr($newAnr) - ->setReferential($newReferential) - ->setCategory($categoryNewIds[$measure->category->id]) - ->setMeasuresLinked(new ArrayCollection()) - ->setAmvs(new ArrayCollection()) - ->setRolfRisks(new ArrayCollection()); - $measuresNewIds[$measure->getUuid()] = $newMeasure; - $newMeasures[] = $newMeasure; - } - $newReferential->setMeasures($newMeasures); - - $referentialTable->save($newReferential, false); - $referentialTable->getDb()->flush(); - } + /* Recreate the source's or core's referential in the analysis. */ + $referential = (new Entity\Referential()) + ->setUuid($referentialUuid) + ->setAnr($anr) + ->setLabels($referentialFromSource->getLabels()) + ->setUuid($referentialFromSource->getUuid()) + ->setCreator($this->connectedUser->getEmail()); - // duplicate measures-measures - $measuresmeasures = $this->get('measureMeasureCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($measuresmeasures as $mm) { - $newMeasureMeasure = new MeasureMeasure($mm); - $newMeasureMeasure->setAnr($newAnr); - $this->get('measureMeasureCliTable')->save($newMeasureMeasure, false); - } - } + $this->referentialTable->save($referential, false); + $linkedReferentialUuids[] = $referential->getUuid(); - //duplicate SoaScaleComment - $anrSoaScaleCommentOldIdsToNewObjectsMap = $this->createSoaScaleCommentFromSource( - $newAnr, - $anr, - $source, - $connectedUser - ); - - // duplicate soas - if ($source == MonarcObject::SOURCE_COMMON) { - foreach ($measuresNewIds as $key => $value) { - $newSoa = new Soa(); - $newSoa->set('id', null); - $newSoa->setAnr($newAnr); - $newSoa->setMeasure($value); - $newSoa->setSoaScaleComment(null); - $this->get('soaTable')->save($newSoa, false); - } - } else { - $soas = $this->get('soaTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($soas as $soa) { - $newSoa = new Soa($soa); - $newSoa->set('id', null); - $newSoa->setAnr($newAnr); - $newSoa->setMeasure($measuresNewIds[$soa->measure->getUuid()]); - if ($soa->getSoaScaleComment()!== null) { - $newSoa->setSoaScaleComment( - $anrSoaScaleCommentOldIdsToNewObjectsMap[$soa->getSoaScaleComment()->getId()] - ); - } else { - $newSoa->setSoaScaleComment(null); - } - $this->get('soaTable')->save($newSoa, false); - } + $categoriesBySourceIds = []; + foreach ($referentialFromSource->getCategories() as $categoryFromSource) { + $soaCategory = (new Entity\SoaCategory()) + ->setAnr($anr) + ->setReferential($referential) + ->setLabels($categoryFromSource->getLabels()); + $this->soaCategoryTable->save($soaCategory, false); + $categoriesBySourceIds[$categoryFromSource->getId()] = $soaCategory; } - // duplicate amvs - $amvsNewIds = []; - $amvs = $source === MonarcObject::SOURCE_COMMON - ? $this->get('amvTable')->fetchAllObject() - : $this->get('amvCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($amvs as $key => $amv) { - if (!isset( - $assetsNewIds[$amv->asset->getUuid()], - $threatsNewIds[$amv->threat->getUuid()], - $vulnerabilitiesNewIds[$amv->vulnerability->getUuid()] - )) { - unset($amvs[$key]); - } - } - foreach ($amvs as $amv) { - $newAmv = new Amv($amv); - $newAmv->setAnr($newAnr); - $newAmv->setAsset($assetsNewIds[$amv->getAsset()->getUuid()]); - $newAmv->setThreat($threatsNewIds[$amv->getThreat()->getUuid()]); - $newAmv->setVulnerability($vulnerabilitiesNewIds[$amv->getVulnerability()->getUuid()]); - $newAmv->setMeasures(null); - foreach ($amv->getMeasures() as $measure) { - if (isset($measuresNewIds[$measure->getUuid()])) { - $measuresNewIds[$measure->getUuid()]->addAmv($newAmv); + /* Recreates the measures in the analysis. */ + foreach ($referentialFromSource->getMeasures() as $measureFromSource) { + $measure = (new Entity\Measure()) + ->setUuid($measureFromSource->getUuid()) + ->setAnr($anr) + ->setCode($measureFromSource->getCode()) + ->setLabels($measureFromSource->getLabels()) + ->setStatus($measureFromSource->getStatus()) + ->setReferential($referential) + ->setCategory($categoriesBySourceIds[$measureFromSource->getCategory()->getId()]) + ->setCreator($this->connectedUser->getEmail()); + /* Recreate measures (controls) mapping links across different referential. */ + foreach ($measureFromSource->getLinkedMeasures() as $linkedMeasureFromSource) { + /* Validate if the referential of the linked measure is already create, + otherwise it will be linked later if the referential is added to the analysis. */ + if (!\in_array( + $linkedMeasureFromSource->getReferential()->getUuid(), + $linkedReferentialUuids, + true + )) { + continue; } - } - $this->get('amvCliTable')->save($newAmv, false); - $amvsNewIds[$amv->getUuid()] = $newAmv; - } - - // duplicate rolf tags - $rolfTagsNewIds = []; - $rolfTags = ($source == MonarcObject::SOURCE_COMMON) - ? $this->get('rolfTagTable')->fetchAllObject() - : $this->get('rolfTagCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($rolfTags as $rolfTag) { - $newRolfTag = new RolfTag($rolfTag); - $newRolfTag->set('id', null); - $newRolfTag->setAnr($newAnr); - $newRolfTag->set('risks', []); - $this->get('rolfTagCliTable')->save($newRolfTag, false); - $rolfTagsNewIds[$rolfTag->id] = $newRolfTag; - } - // duplicate rolf risk - $rolfRisksNewIds = []; - $rolfRisks = ($source == MonarcObject::SOURCE_COMMON) - ? $this->get('rolfRiskTable')->fetchAllObject() - : $this->get('rolfRiskCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($rolfRisks as $rolfRisk) { - $newRolfRisk = new RolfRisk($rolfRisk); - $newRolfRisk->set('id', null); - $newRolfRisk->setAnr($newAnr); - $newRolfRisk->measures = new ArrayCollection; - // Link tags - $indexTagRisk = 0; - $listTagrisk = []; - foreach ($rolfRisk->tags as $key => $tag) { - if (!empty($rolfTagsNewIds[$tag->id])) { - $listTagrisk[$indexTagRisk]=$rolfTagsNewIds[$tag->id]; - $indexTagRisk++; + /* Validates if the linked measure from the common DB presented in the client's DB. */ + $linkedMeasure = $createdMeasuresUuidsToObjects[$linkedMeasureFromSource->getUuid()] + ?? $this->measureTable->findByUuidAndAnr($linkedMeasureFromSource->getUuid(), $anr); + if ($linkedMeasure === null) { + continue; } + /* Recreates the bi-directional links that are defined on the BackOffice side / common DB. */ + $measure->addLinkedMeasure($linkedMeasure); } - $newRolfRisk->setTags($listTagrisk); - //link the measures - - foreach ($rolfRisk->measures as $m) { - try { - $measure = $this->get('measureCliTable')->getEntity([ - 'anr' => $newAnr->getId(), - 'uuid' => $m->getUuid() - ]); - $measure->addOpRisk($newRolfRisk); - } catch (Exception $e) { - } //needed if the measures don't exist in the client ANR - } - $this->get('rolfRiskCliTable')->save($newRolfRisk, false); - $rolfRisksNewIds[$rolfRisk->id] = $newRolfRisk; - } - // duplicate objects categories - /** @var ObjectSuperClass[] $objects */ - $objects = $source === MonarcObject::SOURCE_COMMON - ? $this->get('MonarcObjectTable')->fetchAllObject() - : $this->get('objectCliTable')->getEntityByFields(['anr' => $anr->getId()]); - if ($source === MonarcObject::SOURCE_COMMON) { - foreach ($objects as $key => $object) { - $existInAnr = false; - foreach ($object->getAnrs() as $anrObject) { - if ($anrObject->getId() === $anr->getId()) { - $existInAnr = true; + if ($recreateAmvRolfRiskAndSoaLinks) { + /* Recreate links with AMVs (information risks) and rolf risks (operation) from source's controls */ + foreach ($measureFromSource->getAmvs() as $amvFromSource) { + $amv = $this->amvTable->findByAmvItemsUuidsAndAnr( + $amvFromSource->getAsset()->getUuid(), + $amvFromSource->getThreat()->getUuid(), + $amvFromSource->getVulnerability()->getUuid(), + $anr + ); + if ($amv !== null) { + $measure->addAmv($amv); } } - if (!$existInAnr) { - unset($objects[$key]); + foreach ($measureFromSource->getRolfRisks() as $rolfRiskFromSource) { + $rolfRisk = $this->rolfRiskTable->findByAnrAndCode($anr, $rolfRiskFromSource->getCode()); + if ($rolfRisk !== null + && $rolfRisk->getLabel($anr->getLanguage()) === $rolfRiskFromSource + ->getLabel($anr->getLanguage()) + ) { + $measure->addRolfRisk($rolfRisk); + } } + + /* Recreate SOA link with measure. */ + $this->soaTable->save((new Entity\Soa())->setAnr($anr)->setMeasure($measure), false); } + + $this->measureTable->save($measure, false); + $createdMeasuresUuidsToObjects[$measure->getUuid()] = $measure; } - $categoriesIds = []; - foreach ($objects as $object) { - if ($object->getCategory()) { - $categoriesIds[] = $object->getCategory()->getId(); - $this->getParentsCategoryIds($object->getCategory(), $categoriesIds); - } - } + } - $objectsCategoriesNewIds = []; - /** @var ObjectCategorySuperClass[] $objectsCategories */ - $objectsCategories = $source === MonarcObject::SOURCE_COMMON - ? $this->get('objectCategoryTable')->fetchAllObject() - : $this->get('objectCategoryCliTable')->getEntityByFields( - ['anr' => $anr->getId()], - ['parent' => 'ASC'] - ); - foreach ($objectsCategories as $objectCategory) { - if (\in_array($objectCategory->getId(), $categoriesIds, true)) { - $newObjectCategory = new ObjectCategory($objectCategory); - $newObjectCategory->set('id', null); - $newObjectCategory->setAnr($newAnr); - if ($objectCategory->getParent()) { - $newObjectCategory->setParent($objectsCategoriesNewIds[$objectCategory->getParent()->getId()]); - } - if ($objectCategory->getRoot()) { - $newObjectCategory->setRoot($objectsCategoriesNewIds[$objectCategory->getRoot()->getId()]); - } - if (!$objectCategory->getObjects()->isEmpty()) { - $newObjectCategory->resetObjects(); - } - $this->get('objectCategoryCliTable')->save($newObjectCategory, false); + return $createdMeasuresUuidsToObjects; + } - $objectsCategoriesNewIds[$objectCategory->getId()] = $newObjectCategory; - } - } + private function setCurrentAnrToConnectedUser(Entity\Anr $anr, bool $saveInDb = false): void + { + $this->userTable->save($this->connectedUser->setCurrentAnr($anr), $saveInDb); + } - // duplicate objects - $objectsNewIds = []; - $objectsRootCategories = []; - /** @var CoreObjectCategoryTable|ObjectCategoryTable $objectCategoryTable */ - $objectCategoryTable = $source === MonarcObject::SOURCE_COMMON - ? $this->get('objectCategoryTable') - : $this->get('objectCategoryCliTable'); - foreach ($objects as $object) { - $newObject = new MonarcObject($object); - $newObject->setAnr($newAnr); - $newObject->resetAnrs(); - $newObject->addAnr($newAnr); - if ($object->getCategory() !== null) { - $newObject->setCategory($objectsCategoriesNewIds[$object->getCategory()->getId()]); - - $objectCategory = $objectCategoryTable->findById($object->getCategory()->getId()); - $rootCategoryId = $objectCategory->getRoot() !== null - ? $objectCategory->getRoot()->getId() - : $objectCategory->getId(); - if (!\in_array($rootCategoryId, $objectsRootCategories, true)) { - $objectsRootCategories[] = $rootCategoryId; - } - } - $newObject->setAsset($assetsNewIds[$object->getAsset()->getUuid()]); - if ($object->getRolfTag()) { - $newObject->setRolfTag($rolfTagsNewIds[$object->getRolfTag()->getId()]); - } - //in FO all the objects are generic - $newObject->setMode(0); //force to be generic - $this->get('objectCliTable')->save($newObject, false); - $objectsNewIds[$object->getUuid()] = $newObject; - } + private function duplicateScales( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon + ): array { + $scalesImpactTypesOldIdsToNewObjects = []; + $scaleTable = $isSourceCommon ? $this->coreScaleTable : $this->scaleTable; + /** @var CoreEntity\ScaleSuperClass $sourceScale */ + foreach ($scaleTable->findByAnr($sourceAnr) as $sourceScale) { + $newScale = (new Entity\Scale($newAnr, [ + 'min' => $sourceScale->getMin(), + 'max' => $sourceScale->getMax(), + 'type' => $sourceScale->getType(), + ]))->setCreator($this->connectedUser->getEmail()); + $this->scaleTable->save($newScale, false); + + foreach ($sourceScale->getScaleImpactTypes() as $sourceScaleImpactType) { + $newScaleImpactType = (new Entity\ScaleImpactType()) + ->setAnr($newAnr) + ->setScale($newScale) + ->setIsHidden($sourceScaleImpactType->isHidden()) + ->setIsSys($sourceScaleImpactType->isSys()) + ->setLabels($sourceScaleImpactType->getLabels()) + ->setType($sourceScaleImpactType->getType()) + ->setCreator($this->connectedUser->getEmail()); + $this->scaleImpactTypeTable->save($newScaleImpactType, false); - // duplicate anrs objects categories - /** @var AnrObjectCategoryTable|CoreAnrObjectCategoryTable $anrObjectCategoryTable */ - $anrObjectCategoryTable = $source === MonarcObject::SOURCE_COMMON - ? $this->get('anrObjectCategoryTable') - : $this->get('anrObjectCategoryCliTable'); - $anrObjectsCategories = $anrObjectCategoryTable->findByAnrOrderedByPosititon($anr); - foreach ($anrObjectsCategories as $key => $anrObjectCategory) { - if (!\in_array($anrObjectCategory->getCategory()->getId(), $objectsRootCategories, true)) { - unset($anrObjectsCategories[$key]); + $scalesImpactTypesOldIdsToNewObjects[$sourceScaleImpactType->getId()] = $newScaleImpactType; + + foreach ($sourceScaleImpactType->getScaleComments() as $sourceScaleComment) { + $this->duplicateScaleComments($newAnr, $newScale, $newScaleImpactType, $sourceScaleComment); } } - foreach ($anrObjectsCategories as $key => $anrObjectCategory) { - $newAnrObjectCategory = new AnrObjectCategory($anrObjectCategory); - $newAnrObjectCategory->set('id', null); - $newAnrObjectCategory->setAnr($newAnr); - $newAnrObjectCategory - ->setCategory($objectsCategoriesNewIds[$anrObjectCategory->getCategory()->getId()]); - $this->get('anrObjectCategoryCliTable')->save($newAnrObjectCategory, false); - } - // duplicate objects objects - $objectsObjects = $source === MonarcObject::SOURCE_COMMON - ? $this->get('objectObjectTable')->fetchAllObject() - : $this->get('objectObjectCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($objectsObjects as $key => $objectObject) { - if (!($objectObject->getFather() && isset($objectsNewIds[$objectObject->getFather()->getUuid()]) - && $objectObject->getChild() && isset($objectsNewIds[$objectObject->getChild()->getUuid()])) - ) { - unset($objectsObjects[$key]); + foreach ($sourceScale->getScaleComments() as $sourceScaleComment) { + if ($sourceScaleComment->getScaleImpactType() === null) { + $this->duplicateScaleComments($newAnr, $newScale, null, $sourceScaleComment); } } - foreach ($objectsObjects as $objectObject) { - $newObjectObject = new ObjectObject($objectObject); - $newObjectObject->setAnr($newAnr); - $newObjectObject->setFather($objectsNewIds[$objectObject->getFather()->getUuid()]); - $newObjectObject->setChild($objectsNewIds[$objectObject->getChild()->getUuid()]); - $this->get('objectObjectCliTable')->save($newObjectObject, false); - } - - //duplicate AnrMetadatasOnInstances - $anrMetadatasOnInstancesOldIdsToNewObjectsMap = $this->createAnrMetadatasOnInstancesFromSource( - $newAnr, - $anr, - $source, - $connectedUser - ); + } - // duplicate instances - $instancesNewIds = []; - /** @var InstanceTable $instanceTable */ - $instanceTable = $source === MonarcObject::SOURCE_COMMON - ? $this->get('instanceTable') - : $this->get('instanceCliTable'); - $instances = $instanceTable->getEntityByFields(['anr' => $anr->getId()], ['parent' => 'ASC']); - foreach ($instances as $instance) { - $newInstance = new Instance($instance); - $newInstance->set('id', null); - $newInstance->setAnr($newAnr); - $newInstance->setAsset($assetsNewIds[$instance->getAsset()->getUuid()]); - $newInstance->setObject($objectsNewIds[$instance->getObject()->getUuid()]); - $newInstance->setRoot(null); - $newInstance->setParent(null); - /* - * TODO: remove the reset method when all the entities creation from another entities wil be forbidden. - * Currently we link the core related classes, that's why have to clean up the relations. - */ - $newInstance->resetInstanceRisks(); - $newInstance->resetInstanceConsequences(); - if ($source !== MonarcObject::SOURCE_COMMON) { - $this->createInstanceMetadatasFromSource( - $connectedUser, - $instance, - $newInstance, - $anr, - $newAnr, - $anrMetadatasOnInstancesOldIdsToNewObjectsMap - ); - } + return $scalesImpactTypesOldIdsToNewObjects; + } - $this->get('instanceCliTable')->save($newInstance, false); - $instancesNewIds[$instance->id] = $newInstance; - } - foreach ($instances as $instance) { - if ($instance->getRoot() || $instance->getParent()) { - $newInstance = $instancesNewIds[$instance->getId()]; - if ($instance->getRoot()) { - $newInstance->setRoot($instancesNewIds[$instance->getRoot()->getId()]); - } - if ($instance->getParent()) { - $newInstance->setParent($instancesNewIds[$instance->getParent()->getId()]); - } - $this->get('instanceCliTable')->save($newInstance, false); - } - } + private function duplicateScaleComments( + Entity\Anr $newAnr, + Entity\Scale $newScale, + ?Entity\ScaleImpactType $newScaleImpactType, + CoreEntity\ScaleCommentSuperClass $sourceScaleComment + ): void { + $newScaleComment = (new Entity\ScaleComment()) + ->setAnr($newAnr) + ->setScale($newScale) + ->setScaleIndex($sourceScaleComment->getScaleIndex()) + ->setScaleValue($sourceScaleComment->getScaleValue()) + ->setComments($sourceScaleComment->getComments()) + ->setCreator($this->connectedUser->getEmail()); + if ($newScaleImpactType !== null) { + $newScaleComment->setScaleImpactType($newScaleImpactType); + } - $scalesImpactTypesOldIdsToNewObjectsMap = $this->createScalesFromSourceAnr( - $newAnr, - $anr, - $source, - $connectedUser - ); + $this->scaleCommentTable->save($newScaleComment, false); + } - $operationalScaleTypesOldIdsToNewObjectsMap = $this->createOperationalRiskScalesFromSourceAnr( - $newAnr, - $anr, - $source, - $connectedUser + private function duplicateOperationalRiskScales( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon + ): array { + $sourceTranslations = []; + if ($isSourceCommon) { + $sourceTranslations = $this->coreTranslationTable->findByAnrTypesAndLanguageIndexedByKey( + $sourceAnr, + [ + CoreEntity\TranslationSuperClass::OPERATIONAL_RISK_SCALE_TYPE, + CoreEntity\TranslationSuperClass::OPERATIONAL_RISK_SCALE_COMMENT, + ], + $newAnr->getLanguageCode() ); + } - // duplicate instances risks - /** @var InstanceRiskTable $instanceRiskCliTable */ - $instanceRiskCliTable = $this->get('instanceRiskCliTable'); - /** @var InstanceRiskTable|CoreInstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $source === MonarcObject::SOURCE_COMMON - ? $this->get('instanceRiskTable') - : $instanceRiskCliTable; - $instancesRisks = $instanceRiskTable->findByAnr($anr); - $instancesRisksNewIds = []; - foreach ($instancesRisks as $instanceRisk) { - $newInstanceRisk = new InstanceRisk($instanceRisk); - $newInstanceRisk->set('id', null); - $newInstanceRisk->setAnr($newAnr); - if ($instanceRisk->getAmv()) { - $newInstanceRisk->setAmv($amvsNewIds[$instanceRisk->getAmv()->getUuid()]); - } - if ($instanceRisk->getAsset()) { - $newInstanceRisk->setAsset($assetsNewIds[$instanceRisk->getAsset()->getUuid()]); - } - if ($instanceRisk->getThreat()) { - $newInstanceRisk->setThreat($threatsNewIds[$instanceRisk->getThreat()->getUuid()]); - } - if ($instanceRisk->getVulnerability()) { - $newInstanceRisk->setVulnerability($vulnerabilitiesNewIds[ - $instanceRisk->getVulnerability()->getUuid()]); - } - if ($instanceRisk->getInstance()) { - $newInstanceRisk->setInstance($instancesNewIds[$instanceRisk->getInstance()->getId()]); - } - if ($instanceRisk->getInstanceRiskOwner()) { - $instanceRiskOwner = $this->getOrCreateInstanceRiskOwner( - $newAnr, - $instanceRisk->getInstanceRiskOwner()->getName(), - $connectedUser - ); - $newInstanceRisk->setInstanceRiskOwner($instanceRiskOwner); + $operationalScaleTypesOldIdsToNewObjects = []; + $sourceOperationalRiskScaleTable = $isSourceCommon + ? $this->coreOperationalRiskScaleTable + : $this->operationalRiskScaleTable; + /** @var CoreEntity\OperationalRiskScaleSuperClass $sourceOperationalRiskScale */ + foreach ($sourceOperationalRiskScaleTable->findByAnr($sourceAnr) as $sourceOperationalRiskScale) { + $newOperationalRiskScale = (new Entity\OperationalRiskScale()) + ->setAnr($newAnr) + ->setType($sourceOperationalRiskScale->getType()) + ->setMin($sourceOperationalRiskScale->getMin()) + ->setMax($sourceOperationalRiskScale->getMax()) + ->setCreator($this->connectedUser->getEmail()); + + foreach ($sourceOperationalRiskScale->getOperationalRiskScaleTypes() as $operationalRiskScaleType) { + if ($isSourceCommon) { + /** @var CoreEntity\OperationalRiskScaleType $operationalRiskScaleType */ + $label = isset($sourceTranslations[$operationalRiskScaleType->getLabelTranslationKey()]) + ? $sourceTranslations[$operationalRiskScaleType->getLabelTranslationKey()]->getValue() + : ''; + } else { + /** @var Entity\OperationalRiskScaleType $operationalRiskScaleType */ + $label = $operationalRiskScaleType->getLabel(); } - $newInstanceRisk->setContext($instanceRisk->getContext()); + $newOperationalRiskScaleType = (new Entity\OperationalRiskScaleType()) + ->setAnr($newAnr) + ->setOperationalRiskScale($newOperationalRiskScale) + ->setLabel($label) + ->setIsHidden($operationalRiskScaleType->isHidden()) + ->setCreator($this->connectedUser->getEmail()); - $instanceRiskCliTable->saveEntity($newInstanceRisk, false); - $instancesRisksNewIds[$instanceRisk->getId()] = $newInstanceRisk; - } + $this->operationalRiskScaleTypeTable->save($newOperationalRiskScaleType, false); - // duplicate instances risks op - /** @var InstanceRiskOpTable $instanceRiskOpCliTable */ - $instanceRiskOpCliTable = $this->get('instanceRiskOpCliTable'); - /** @var CoreInstanceRiskOpTable|InstanceRiskOpTable $instanceRiskOpTable */ - $instanceRiskOpTable = $source === MonarcObject::SOURCE_COMMON - ? $this->get('instanceRiskOpTable') - : $instanceRiskOpCliTable; - $instancesRisksOp = $instanceRiskOpTable->findByAnr($anr); - $instancesRisksOpNewIds = []; - foreach ($instancesRisksOp as $instanceRiskOp) { - $newInstanceRiskOp = (new InstanceRiskOp()) - ->setAnr($newAnr) - ->setInstance($instancesNewIds[$instanceRiskOp->getInstance()->getId()]) - ->setObject($objectsNewIds[$instanceRiskOp->getObject()->getUuid()]) - ->setKindOfMeasure($instanceRiskOp->getKindOfMeasure()) - ->setBrutProb($instanceRiskOp->getBrutProb()) - ->setNetProb($instanceRiskOp->getNetProb()) - ->setTargetedProb($instanceRiskOp->getTargetedProb()) - ->setCacheBrutRisk($instanceRiskOp->getCacheBrutRisk()) - ->setCacheNetRisk($instanceRiskOp->getCacheNetRisk()) - ->setCacheTargetedRisk($instanceRiskOp->getCacheTargetedRisk()) - ->setMitigation($instanceRiskOp->getMitigation()) - ->setSpecific($instanceRiskOp->getSpecific()) - ->setRiskCacheCode($instanceRiskOp->getRiskCacheCode()) - ->setRiskCacheLabels([ - 'riskCacheLabel1' => $instanceRiskOp->getRiskCacheLabel(1), - 'riskCacheLabel2' => $instanceRiskOp->getRiskCacheLabel(2), - 'riskCacheLabel3' => $instanceRiskOp->getRiskCacheLabel(3), - 'riskCacheLabel4' => $instanceRiskOp->getRiskCacheLabel(4), - ]) - ->setRiskCacheDescriptions([ - 'riskCacheDescription1' => $instanceRiskOp->getRiskCacheDescription(1), - 'riskCacheDescription2' => $instanceRiskOp->getRiskCacheDescription(2), - 'riskCacheDescription3' => $instanceRiskOp->getRiskCacheDescription(3), - 'riskCacheDescription4' => $instanceRiskOp->getRiskCacheDescription(4), - ]) - ->setComment($instanceRiskOp->getComment()) - ->setContext($instanceRiskOp->getContext()) - ->setCreator($connectedUser->getEmail()) - ->resetUpdatedAtValue(); - if ($instanceRiskOp->getRolfRisk()) { - $newInstanceRiskOp->setRolfRisk($rolfRisksNewIds[$instanceRiskOp->getRolfRisk()->getId()]); - } + $operationalScaleTypesOldIdsToNewObjects[$operationalRiskScaleType->getId()] + = $newOperationalRiskScaleType; - if ($instanceRiskOp->getInstanceRiskOwner()) { - $instanceRiskOwner = $this->getOrCreateInstanceRiskOwner( + foreach ($operationalRiskScaleType->getOperationalRiskScaleComments() as $operationalRiskScaleComment) { + $this->duplicateOperationalRiskScaleComments( $newAnr, - $instanceRiskOp->getInstanceRiskOwner()->getName(), - $connectedUser + $newOperationalRiskScale, + $newOperationalRiskScaleType, + $operationalRiskScaleComment, + $sourceTranslations ); - $newInstanceRiskOp->setInstanceRiskOwner($instanceRiskOwner); } + } - $instanceRiskOpCliTable->saveEntity($newInstanceRiskOp, false); + foreach ($sourceOperationalRiskScale->getOperationalRiskScaleComments() as $operationalRiskScaleComment) { + if ($operationalRiskScaleComment->getOperationalRiskScaleType() !== null) { + continue; + } - $this->createOperationalInstanceRiskScalesFromSource( - $instanceRiskOp, - $operationalScaleTypesOldIdsToNewObjectsMap, + $this->duplicateOperationalRiskScaleComments( $newAnr, - $newInstanceRiskOp, - $connectedUser - ); - - $instancesRisksOpNewIds[$instanceRiskOp->getId()] = $newInstanceRiskOp; - } - - //duplicate instances consequences - /** @var InstanceConsequenceTable|CoreInstanceConsequenceTable $instanceConsequenceTable */ - $instanceConsequenceTable = $source === MonarcObject::SOURCE_COMMON - ? $this->get('instanceConsequenceTable') - : $this->get('instanceConsequenceCliTable'); - $instancesConsequences = $instanceConsequenceTable->findByAnr($anr); - foreach ($instancesConsequences as $instanceConsequence) { - $newInstanceConsequence = new InstanceConsequence($instanceConsequence); - $newInstanceConsequence->set('id', null); - $newInstanceConsequence->setAnr($newAnr); - $newInstanceConsequence->setInstance($instancesNewIds[$instanceConsequence->getInstance()->getId()]); - $newInstanceConsequence->setObject($objectsNewIds[$instanceConsequence->getObject()->getUuid()]); - $newInstanceConsequence->setScaleImpactType( - $scalesImpactTypesOldIdsToNewObjectsMap[$instanceConsequence->getScaleImpactType()->getId()] + $newOperationalRiskScale, + null, + $operationalRiskScaleComment, + $sourceTranslations ); - $this->get('instanceConsequenceCliTable')->save($newInstanceConsequence, false); - } - - // duplicate questions & choices - $questions = $source === MonarcObject::SOURCE_COMMON - ? $this->get('questionTable')->fetchAllObject() - : $this->get('questionCliTable')->getEntityByFields(['anr' => $anr->id]); - $questionsNewIds = []; - foreach ($questions as $q) { - $newQuestion = new Question($q); - $newQuestion->set('id', null); - $newQuestion->set('anr', $newAnr); - $this->get('questionCliTable')->save($newQuestion, false); - $questionsNewIds[$q->id] = $newQuestion; } - $questionChoices = $source === MonarcObject::SOURCE_COMMON - ? $this->get('questionChoiceTable')->fetchAllObject() - : $this->get('questionChoiceCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($questionChoices as $qc) { - $newQuestionChoice = new QuestionChoice($qc); - $newQuestionChoice->set('id', null); - $newQuestionChoice->set('anr', $newAnr); - $newQuestionChoice->set('question', $questionsNewIds[$qc->get('question')->get('id')]); - $this->get('questionChoiceCliTable')->save($newQuestionChoice, false); - } - - //if we are duplicating an analysis do the following - if ($source === MonarcObject::SOURCE_CLIENT) { - //duplicate interviews - $interviews = $this->get('interviewCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($interviews as $interview) { - $newInterview = new Interview($interview); - $newInterview->set('id', null); - $newInterview->setAnr($newAnr); - $this->get('interviewCliTable')->save($newInterview, false); - } - - //duplicate record actors - $recordActors = $this->get('recordActorCliTable')->getEntityByFields(['anr' => $anr->id]); - $actorNewIds = []; - foreach ($recordActors as $a) { - $newActor = new RecordActor($a); - $newActor->set('id', null); - $newActor->setAnr($newAnr); - $this->get('recordActorCliTable')->save($newActor, false); - $this->get('recordActorCliTable')->getDb()->flush(); - $actorNewIds[$a->id] = $newActor; - } - //duplicate record data categories - $recordDataCategoryTable = $this->get('recordDataCategoryCliTable'); - $recordDataCategories = $recordDataCategoryTable->getEntityByFields(['anr' => $anr->id]); - $dataCategoryNewIds = []; - foreach ($recordDataCategories as $dc) { - $newDataCategory = new RecordDataCategory($dc); - $newDataCategory->set('id', null); - $newDataCategory->setAnr($newAnr); - $recordDataCategoryTable->save($newDataCategory, true); - $dataCategoryNewIds[$dc->id] = $newDataCategory; - } - - //duplicate record processors - $recordProcessors = $this->get('recordProcessorCliTable')->getEntityByFields(['anr' => $anr->id]); - $processorNewIds = []; - foreach ($recordProcessors as $p) { - $newProcessor = new RecordProcessor($p); - $newProcessor->set('id', null); - $newProcessor->setAnr($newAnr); - $activities = []; - $newProcessor->setActivities($activities); - $secMeasures = []; - $newProcessor->setSecMeasures($secMeasures); - if ($p->representative != null) { - $newProcessor->setRepresentative($actorNewIds[$p->representative->id]); - } - if ($p->dpo != null) { - $newProcessor->setDpo($actorNewIds[$p->dpo->id]); - } - $this->get('recordProcessorCliTable')->save($newProcessor, false); - $this->get('recordProcessorCliTable')->getDb()->flush(); - $processorNewIds[$p->id] = $newProcessor; - } - - //duplicate record recipients - $recordRecipients = $this->get('recordRecipientCliTable')->getEntityByFields(['anr' => $anr->id]); - $recipientNewIds = []; - foreach ($recordRecipients as $r) { - $newRecipient = new RecordRecipient($r); - $newRecipient->set('id', null); - $newRecipient->setAnr($newAnr); - $this->get('recordRecipientCliTable')->save($newRecipient, false); - $this->get('recordRecipientCliTable')->getDb()->flush(); - $recipientNewIds[$r->id] = $newRecipient; - } - //duplicate record - $records = $this->get('recordCliTable')->getEntityByFields(['anr' => $anr->id]); - $recordNewIds = []; - foreach ($records as $record) { - $newRecord = new Record($record); - $newRecord->set('id', null); - $newRecord->setAnr($newAnr); - if ($record->controller != null) { - $newRecord->setController($actorNewIds[$record->controller->id]); - } - if ($record->representative != null) { - $newRecord->setRepresentative($actorNewIds[$record->representative->id]); - } - if ($record->dpo != null) { - $newRecord->setDpo($actorNewIds[$record->dpo->id]); - } - - $jointControllerNewIds = []; - $jointControllers = $record->getJointControllers(); - foreach ($jointControllers as $jc) { - $jointControllerNewIds[] = $actorNewIds[$jc->id]; - } - $newRecord->setJointControllers($jointControllerNewIds); - - $processorIds = []; - $processors = $record->getProcessors(); - foreach ($processors as $p) { - $processorIds[] = $processorNewIds[$p->id]; - } - $newRecord->setProcessors($processorIds); - - $recipientIds = []; - $recipients = $record->getRecipients(); - foreach ($recipients as $r) { - $recipientIds[$r->id] = $recipientNewIds[$r->id]; - } - $newRecord->setRecipients($recipientIds); - - $this->get('recordCliTable')->save($newRecord, false); - $this->get('recordCliTable')->getDb()->flush(); - $recordNewIds[$record->id] = $newRecord; - } - - foreach ($recordProcessors as $p) { - $data = []; - $activities = $p->getActivities(); - foreach ($activities as $recordId => $value) { - $data["activities"][$recordNewIds[$recordId]->getId()] = $value; - } - $secMeasures = $p->getSecMeasures(); - foreach ($secMeasures as $recordId => $value) { - $data["secMeasures"][$recordNewIds[$recordId]->getId()] = $value; - } - $this->recordProcessorService->patch($processorNewIds[$p->id]->getId(), $data); - } - - //duplicate record personal data - $recordPersonalData = $this->get('recordPersonalDataCliTable')->getEntityByFields(['anr' => $anr->id]); - $personalDataNewIds = []; - foreach ($recordPersonalData as $pd) { - $newPersonalData = new RecordPersonalData($pd); - $newPersonalData->set('id', null); - $newPersonalData->setAnr($newAnr); - $newPersonalData->setRecord($recordNewIds[$pd->record->id]); - $newDataCategoryIds = []; - $dataCategories = $pd->getDataCategories(); - foreach ($dataCategories as $dc) { - $newDataCategoryIds[] = $dataCategoryNewIds[$dc->id]; - } - $newPersonalData->setDataCategories($newDataCategoryIds); - $this->get('recordPersonalDataCliTable')->save($newPersonalData, false); - $this->get('recordPersonalDataCliTable')->getDb()->flush(); - $personalDataNewIds[$pd->id] = $newPersonalData; - } - - //duplicate record international transfers - $recordInternationalTransfers = $this->get('recordInternationalTransferCliTable') - ->getEntityByFields(['anr' => $anr->id]); - $internationalTransferNewIds = []; - foreach ($recordInternationalTransfers as $it) { - $newInternationalTransfer = new RecordInternationalTransfer($it); - $newInternationalTransfer->set('id', null); - $newInternationalTransfer->setAnr($newAnr); - $newInternationalTransfer->setRecord($recordNewIds[$it->record->id]); - $this->get('recordInternationalTransferCliTable')->save($newInternationalTransfer, false); - $this->get('recordInternationalTransferCliTable')->getDb()->flush(); - $internationalTransferNewIds[$it->id] = $newInternationalTransfer; - } - - $recommendationsNewIds = []; - // duplicate recommandations sets and recommandations - /** @var RecommandationSet[] $recommendationsSets */ - $recommendationsSets = $this->get('recommandationSetCliTable')->getEntityByFields(['anr' => $anr->id]); - foreach ($recommendationsSets as $recommendationSet) { - $recommendationSetRecommendations = []; - - $recommendations = $recommendationSet->getRecommandations(); - $recommendationSet->setRecommandations(null); - $newRecommendationSet = new RecommandationSet($recommendationSet); - $newRecommendationSet->setAnr($newAnr); - - foreach ($recommendations as $recommandation) { - $newRecommandation = new Recommandation($recommandation); - $newRecommandation->setAnr($newAnr); - $newRecommandation->setRecommandationSet($newRecommendationSet); - $this->recommendationTable->saveEntity($newRecommandation, false); - $recommendationSetRecommendations[] = $newRecommandation; - $recommendationsNewIds[$recommandation->getUuid()] = $newRecommandation; - } - - $newRecommendationSet->setRecommandations($recommendationSetRecommendations); - $this->get('recommandationSetCliTable')->save($newRecommendationSet, false); - } - - // duplicate recommendations historics - $recommandationsHistorics = $this->get('recommandationHistoricCliTable') - ->getEntityByFields(['anr' => $anr->id]); - foreach ($recommandationsHistorics as $recommandationHistoric) { - $newRecommandationHistoric = new RecommandationHistoric($recommandationHistoric); - $newRecommandationHistoric->set('id', null); - $newRecommandationHistoric->setAnr($newAnr); - $this->get('recommandationHistoricCliTable')->save($newRecommandationHistoric, false); - } + $this->operationalRiskScaleTable->save($newOperationalRiskScale, false); + } - //duplicate recommandations risks - /** @var RecommandationRiskTable $recommendationRiskTable */ - $recommendationRiskTable = $this->get('recommandationRiskCliTable'); - $recommandationsRisks = $recommendationRiskTable->findByAnr($anr); - foreach ($recommandationsRisks as $recommandationRisk) { - $newRecommendationRisk = (new RecommandationRisk()) - ->setAnr($newAnr) - ->setCommentAfter($recommandationRisk->getCommentAfter()) - ->setRecommandation( - $recommendationsNewIds[$recommandationRisk->getRecommandation()->getUuid()] - ) - ->setInstance($instancesNewIds[$recommandationRisk->getInstance()->getId()]); - - if ($recommandationRisk->getInstanceRisk()) { - $newRecommendationRisk->setInstanceRisk( - $instancesRisksNewIds[$recommandationRisk->getInstanceRisk()->getId()] - ); - } - if ($recommandationRisk->getInstanceRiskOp()) { - $newRecommendationRisk->setInstanceRiskOp( - $instancesRisksOpNewIds[$recommandationRisk->getInstanceRiskOp()->getId()] - ); - // TODO: remove when #240 is done. - $newRecommendationRisk->setAnr(null); - } - if ($recommandationRisk->getGlobalObject() - && isset($objectsNewIds[$recommandationRisk->getGlobalObject()->getUuid()]) - ) { - $newRecommendationRisk->setGlobalObject( - $objectsNewIds[$recommandationRisk->getGlobalObject()->getUuid()] - ); - } - if ($recommandationRisk->getAsset()) { - $newRecommendationRisk->setAsset($assetsNewIds[$recommandationRisk->getAsset()->getUuid()]); - } - if ($recommandationRisk->getThreat()) { - $newRecommendationRisk->setThreat( - $threatsNewIds[$recommandationRisk->getThreat()->getUuid()] - ); - } - if ($recommandationRisk->getVulnerability()) { - $newRecommendationRisk->setVulnerability( - $vulnerabilitiesNewIds[$recommandationRisk->getVulnerability()->getUuid()] - ); - } - /* - * We do this trick becasue the other relations (asset, threat, vulnerability) - * in case of operation risks are null and the anr will be force reset to null. - * TODO: remove when #240 is done. - */ - if ($newRecommendationRisk->getAnr() === null) { - $recommendationRiskTable->saveEntity($newRecommendationRisk); - $newRecommendationRisk->setAnr($newAnr); - } + return $operationalScaleTypesOldIdsToNewObjects; + } - $recommendationRiskTable->saveEntity($newRecommendationRisk, false); - } - } + /** + * @param CoreEntity\Translation[] $sourceTranslations + */ + private function duplicateOperationalRiskScaleComments( + Entity\Anr $newAnr, + Entity\OperationalRiskScale $newOperationalRiskScale, + ?Entity\OperationalRiskScaleType $newOperationalRiskScaleType, + CoreEntity\OperationalRiskScaleCommentSuperClass $sourceOperationalRiskScaleComment, + array $sourceTranslations + ): void { + if ($sourceOperationalRiskScaleComment instanceof CoreEntity\OperationalRiskScaleComment) { + $comment = isset($sourceTranslations[$sourceOperationalRiskScaleComment->getLabelTranslationKey()]) + ? $sourceTranslations[$sourceOperationalRiskScaleComment->getLabelTranslationKey()]->getValue() + : ''; + } else { + /** @var Entity\OperationalRiskScaleComment $sourceOperationalRiskScaleComment */ + $comment = $sourceOperationalRiskScaleComment->getComment(); + } + $newOperationalRiskScaleComment = (new Entity\OperationalRiskScaleComment()) + ->setAnr($newAnr) + ->setScaleIndex($sourceOperationalRiskScaleComment->getScaleIndex()) + ->setScaleValue($sourceOperationalRiskScaleComment->getScaleValue()) + ->setComment($comment) + ->setOperationalRiskScale($newOperationalRiskScale) + ->setIsHidden($sourceOperationalRiskScaleComment->isHidden()) + ->setCreator($this->connectedUser->getEmail()); + if ($newOperationalRiskScaleType !== null) { + $newOperationalRiskScaleComment->setOperationalRiskScaleType($newOperationalRiskScaleType); + } - $this->get('table')->getDb()->flush(); + $this->operationalRiskScaleCommentTable->save($newOperationalRiskScaleComment, false); + } - if (!$isSnapshot) { - $this->setUserCurrentAnr($newAnr->getId()); - } - } catch (\Exception $e) { - if (!empty($newAnr)) { - $anrCliTable->deleteEntity($newAnr); + private function duplicateAssets( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon + ): array { + $assetsOldIdsToNewObjects = []; + if ($isSourceCommon) { + $assets = $this->coreAssetTable->findByMode(CoreEntity\AssetSuperClass::MODE_GENERIC); + /** @var CoreEntity\Anr $sourceAnr */ + if (!$sourceAnr->getModel()->isGeneric()) { + $assets = array_merge($assets, $sourceAnr->getModel()->getAssets()); } - throw new Exception('Error during analysis creation', 412); + } else { + $assets = $this->assetTable->findByAnr($sourceAnr); } - return $newAnr; - } + foreach ($assets as $asset) { + $assetUuid = $asset->getUuid(); + $assetsOldIdsToNewObjects[$assetUuid] = $this->anrAssetService->create( + $newAnr, + array_merge([ + 'uuid' => $assetUuid, + 'code' => $asset->getCode(), + 'type' => $asset->getType(), + 'status' => $asset->getStatus(), + ], $asset->getLabels(), $asset->getDescriptions()), + false + ); + } - /** - * Defines the user's "current" (ie. last visited) ANR to the specified ID - * @param int $anrId The ANR ID - */ - public function setUserCurrentAnr($anrId) - { - //retrieve connected user - /** @var UserTable $userCliTable */ - $userCliTable = $this->get('userCliTable'); - - /** @var CoreUser $connectedUser */ - $connectedUser = $userCliTable->getConnectedUser(); - - //retrieve connected user information - /** @var User $user */ - $user = $userCliTable->findById($connectedUser->getId()); - - //record last anr to user - /** @var AnrTable $anrCliTable */ - $anrCliTable = $this->get('anrCliTable'); - $user->setCurrentAnr($anrCliTable->getEntity($anrId)); - $userCliTable->saveEntity($user); + return $assetsOldIdsToNewObjects; } - /** - * Recursively retrieves parent categories IDs - * @param AnrObjectCategory $category The category for which we want the parents - * @param array $categoriesIds Reference to an array of categories - * @return array The IDs of the categories of all parents - */ - public function getParentsCategoryIds($category, &$categoriesIds) - { - if ($category->parent) { - $categoriesIds[] = $category->parent->id; - $this->getParentsCategoryIds($category->parent, $categoriesIds); + private function duplicateThreats( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon + ): array { + $threatsOldIdsToNewObjects = []; + if ($isSourceCommon) { + $threats = $this->coreThreatTable->findByMode(CoreEntity\ThreatSuperClass::MODE_GENERIC); + /** @var CoreEntity\Anr $sourceAnr */ + if (!$sourceAnr->getModel()->isGeneric()) { + $threats = array_merge($threats, $sourceAnr->getModel()->getThreats()); + } + } else { + $threats = $this->threatTable->findByAnr($sourceAnr); + } - return $categoriesIds; + $themesOldIdsToNewObjects = []; + foreach ($threats as $threat) { + if ($threat->getTheme() !== null && !isset($themesOldIdsToNewObjects[$threat->getTheme()->getId()])) { + $themesOldIdsToNewObjects[$threat->getTheme()->getId()] = $this->anrThemeService->create( + $newAnr, + $threat->getTheme()->getLabels(), + false + ); + } + $threatUuid = $threat->getUuid(); + $threatsOldIdsToNewObjects[$threatUuid] = $this->anrThreatService->create( + $newAnr, + array_merge([ + 'uuid' => $threatUuid, + 'code' => $threat->getCode(), + 'theme' => $threat->getTheme() !== null + ? $themesOldIdsToNewObjects[$threat->getTheme()->getId()] + : null, + 'comment' => $threat->getComment(), + 'c' => $threat->getConfidentiality(), + 'i' => $threat->getIntegrity(), + 'a' => $threat->getAvailability(), + 'trend' => $threat->getTrend(), + 'qualification' => $threat->getQualification(), + 'status' => $threat->getStatus(), + ], $threat->getLabels(), $threat->getDescriptions()), + false + ); } - return []; + return $threatsOldIdsToNewObjects; } - /** - * Returns the color to apply on the ROLF risks - * @param Anr $anr The ANR Object - * @param int $value The risk value - * @param array $classes The classes name to return for low, med and hi risks - * @return mixed One of the value of $classes - */ - public function getColor($anr, $value, $classes = ['green', 'orange', 'alerte']) - { - if ($value <= $anr->get('seuil1')) { - return $classes[0]; - } elseif ($value <= $anr->get('seuil2')) { - return $classes[1]; + private function duplicateVulnerabilities( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon + ): array { + $vulnerabilitiesOldIdsToNewObjects = []; + if ($isSourceCommon) { + $vulnerabilities = $this->coreVulnerabilityTable->findByMode( + CoreEntity\VulnerabilitySuperClass::MODE_GENERIC + ); + /** @var CoreEntity\Anr $sourceAnr */ + if (!$sourceAnr->getModel()->isGeneric()) { + $vulnerabilities = array_merge($vulnerabilities, $sourceAnr->getModel()->getVulnerabilities()); + } } else { - return $classes[2]; + $vulnerabilities = $this->vulnerabilityTable->findByAnr($sourceAnr); } - } - - public function getColorRiskOp($anr, $value, $classes = ['green', 'orange', 'alerte']) - { - if ($value <= $anr->get('seuilRolf1')) { - return $classes[0]; - } elseif ($value <= $anr->get('seuilRolf2')) { - return $classes[1]; - } else { - return $classes[2]; + foreach ($vulnerabilities as $vulnerability) { + $vulnerabilityUuid = $vulnerability->getUuid(); + $vulnerabilitiesOldIdsToNewObjects[$vulnerabilityUuid] = $this->anrVulnerabilityService->create( + $newAnr, + array_merge([ + 'uuid' => $vulnerabilityUuid, + 'code' => $vulnerability->getCode(), + 'status' => $vulnerability->getStatus(), + ], $vulnerability->getLabels(), $vulnerability->getDescriptions()), + false + ); } + + return $vulnerabilitiesOldIdsToNewObjects; } - /** - * @inheritdoc - */ - public function delete($id) - { - /** @var AnrTable $anrTable */ - $anrTable = $this->get('table'); - //retrieve and delete snapshots associated to anr - $snapshots = $this->get('snapshotCliTable')->getEntityByFields(['anrReference' => $id]); - foreach ($snapshots as $s) { - if (!empty($s)) { - $anrTable->delete($s->get('anr')->get('id'), false); + private function duplicateAmvs( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon, + array $assetsOldIdsToNewObjects, + array $threatsOldIdsToNewObjects, + array $vulnerabilitiesOldIdsToNewObjects, + array $createdMeasuresUuidsToObjects + ): array { + $amvsOldIdsToNewObjects = []; + /** @var CoreEntity\AmvSuperClass[] $sourceAmvs */ + $sourceAmvs = $isSourceCommon ? $this->coreAmvTable->findAll() : $this->amvTable->findByAnr($sourceAnr); + foreach ($sourceAmvs as $sourceAmv) { + if (!isset( + $assetsOldIdsToNewObjects[$sourceAmv->getAsset()->getUuid()], + $threatsOldIdsToNewObjects[$sourceAmv->getThreat()->getUuid()], + $vulnerabilitiesOldIdsToNewObjects[$sourceAmv->getVulnerability()->getUuid()] + )) { + continue; } - } - // Try to drop the stats. - try { - $anr = $anrTable->findById($id); - /** @var StatsAnrService $statsAnrService */ - $statsAnrService = $this->get('statsAnrService'); - $statsAnrService->deleteStatsForAnr($anr->getUuid()); - } catch (Throwable $e) { + $newAmv = $this->anrAmvService->createAmvFromPreparedData( + $newAnr, + $assetsOldIdsToNewObjects[$sourceAmv->getAsset()->getUuid()], + $threatsOldIdsToNewObjects[$sourceAmv->getThreat()->getUuid()], + $vulnerabilitiesOldIdsToNewObjects[$sourceAmv->getVulnerability()->getUuid()], + [ + 'uuid' => $sourceAmv->getUuid(), + 'status' => $sourceAmv->getStatus(), + 'setOnlyExactPosition' => true, + 'position' => $sourceAmv->getPosition(), + + ], + false, + false + ); + foreach ($sourceAmv->getMeasures() as $measure) { + if (isset($createdMeasuresUuidsToObjects[$measure->getUuid()])) { + $newAmv->addMeasure($createdMeasuresUuidsToObjects[$measure->getUuid()]); + } + } + $this->amvTable->save($newAmv, false); + $amvsOldIdsToNewObjects[$sourceAmv->getUuid()] = $newAmv; } - return $anrTable->delete($id); + return $amvsOldIdsToNewObjects; } - /** - * Returns an array that specifies in which language the model may be instancied - * @param int $modelId The model ID - * @return array The array of languages that are valid - */ - public function verifyLanguage($modelId) + private function duplicateRolfTags(CoreEntity\AnrSuperClass $sourceAnr, Entity\Anr $newAnr): array { - $languages = [1, 2, 3, 4]; // TODO: why don't use config list ? - $success = []; - foreach ($languages as $lang) { - $success[$lang] = true; - } + $rolfTagsOldIdsToNewObjects = []; + + /** @var CoreEntity\RolfTagSuperClass $sourceRolfTags */ + $sourceRolfTags = $sourceAnr instanceof Entity\Anr + ? $this->rolfTagTable->findByAnr($sourceAnr) + : $this->coreRolfTagTable->findAll(); + foreach ($sourceRolfTags as $sourceRolfTag) { + $newRolfTag = (new Entity\RolfTag()) + ->setAnr($newAnr) + ->setLabels($sourceRolfTag->getLabels()) + ->setCode($sourceRolfTag->getCode()) + ->setCreator($this->connectedUser->getEmail()); - //model - $model = $this->get('modelTable')->getEntity($modelId); - foreach ($languages as $lang) { - if (empty($model->get('label' . $lang))) { - $success[$lang] = false; - } + $this->rolfTagTable->save($newRolfTag, false); + $rolfTagsOldIdsToNewObjects[$sourceRolfTag->getId()] = $newRolfTag; } - //themes, measures, rolf tags, rolf risks, questions and questions choices - $array = [ - 'theme' => 'label', - 'measure' => 'label', - 'rolfRisk' => 'label', - 'rolfTag' => 'label', - 'question' => 'label', - 'questionChoice' => 'label', - ]; - foreach ($array as $key => $value) { - $entities = $this->get($key . 'Table')->fetchAllObject(); - foreach ($entities as $entity) { - foreach ($languages as $lang) { - if (empty($entity->get($value . $lang))) { - $success[$lang] = false; - } - } - } - } + return $rolfTagsOldIdsToNewObjects; + } - if ($model->get('anr')) { - //instances - $instances = $this->get('instanceTable')->getEntityByFields(['anr' => $model->get('anr')->get('id')]); - foreach ($instances as $instance) { - foreach ($languages as $lang) { - if (empty($instance->get('name' . $lang))) { - $success[$lang] = false; - } - if (empty($instance->get('label' . $lang))) { - $success[$lang] = false; - } + private function duplicateRolfRisks( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + array $rolfTagsOldIdsToNewObjects, + array $createdMeasuresUuidsToObjects + ): array { + $rolfRisksOldIdsToNewObjects = []; + /** @var Entity\RolfRisk[] $sourceRolfRisks */ + $sourceRolfRisks = $sourceAnr instanceof Entity\Anr + ? $this->rolfRiskTable->findByAnr($sourceAnr) + : $this->coreRolfRiskTable->findAll(); + foreach ($sourceRolfRisks as $sourceRolfRisk) { + $newRolfRisk = (new Entity\RolfRisk()) + ->setAnr($newAnr) + ->setCode($sourceRolfRisk->getCode()) + ->setLabels($sourceRolfRisk->getLabels()) + ->setDescriptions($sourceRolfRisk->getDescriptions()) + ->setCreator($this->connectedUser->getEmail()); + + foreach ($sourceRolfRisk->getTags() as $sourceRolfTag) { + if (isset($rolfTagsOldIdsToNewObjects[$sourceRolfTag->getId()])) { + $newRolfRisk->addTag($rolfTagsOldIdsToNewObjects[$sourceRolfTag->getId()]); } } - //scales impact types - $scalesImpactsTypes = $this->get('scaleImpactTypeTable') - ->getEntityByFields(['anr' => $model->get('anr')->get('id')]); - foreach ($scalesImpactsTypes as $scaleImpactType) { - foreach ($languages as $lang) { - if (empty($scaleImpactType->get('label' . $lang))) { - $success[$lang] = false; - } + foreach ($sourceRolfRisk->getMeasures() as $sourceMeasure) { + if (isset($createdMeasuresUuidsToObjects[$sourceMeasure->getUuid()])) { + $newRolfRisk->addMeasure($createdMeasuresUuidsToObjects[$sourceMeasure->getUuid()]); } } - } else { - foreach ($languages as $lang) { - $success[$lang] = false; - } + + $this->rolfRiskTable->save($newRolfRisk, false); + $rolfRisksOldIdsToNewObjects[$sourceRolfRisk->getId()] = $newRolfRisk; } - //assets, threats and vulnerabilities - $array = ['asset', 'threat', 'vulnerability']; - foreach ($array as $value) { - $entities1 = []; - if (!$model->isRegulator) { - $entities1 = $this->get($value . 'Table')->getEntityByFields(['mode' => Asset::MODE_GENERIC]); - } - $entities2 = []; - if (!$model->isGeneric) { - $entities2 = $this->get($value . 'Table')->getEntityByFields(['mode' => Asset::MODE_SPECIFIC]); + return $rolfRisksOldIdsToNewObjects; + } + + private function duplicateAnrMetadataInstanceFields( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon, + ): array { + $commonTranslations = []; + if ($isSourceCommon) { + $commonTranslations = $this->coreTranslationTable->findByAnrTypesAndLanguageIndexedByKey( + $sourceAnr, + [CoreEntity\TranslationSuperClass::ANR_INSTANCE_METADATA_FIELD], + $newAnr->getLanguageCode() + ); + } + $anrInstanceMetadataFieldOldIdsToNewObjects = []; + foreach ($sourceAnr->getAnrInstanceMetadataFields() as $sourceAnrInstanceMetadataField) { + if ($isSourceCommon) { + /** @var CoreEntity\AnrInstanceMetadataField $sourceAnrInstanceMetadataField */ + $label = $commonTranslations[$sourceAnrInstanceMetadataField->getLabelTranslationKey()] ?? ''; + } else { + /** @var Entity\AnrInstanceMetadataField $sourceAnrInstanceMetadataField */ + $label = $sourceAnrInstanceMetadataField->getLabel(); } - $entities = $entities1 + $entities2; - foreach ($entities as $entity) { - foreach ($languages as $lang) { - if (empty($entity->get('label' . $lang))) { - $success[$lang] = false; - } else { - ${$value}[$entity->getUuid()] = $entity->getUuid(); - } - } + $anrInstanceMetadataFieldOldIdsToNewObjects[$sourceAnrInstanceMetadataField->getId()] = $this + ->anrInstanceMetadataFieldService->create( + $newAnr, + [[ + $newAnr->getLanguageCode() => $label, + 'isDeletable' => $sourceAnrInstanceMetadataField->isDeletable(), + ]], + false + ); + } + + return $anrInstanceMetadataFieldOldIdsToNewObjects; + } + + private function duplicateInstanceMetadata( + Entity\Instance $sourceInstance, + Entity\Instance $newInstance, + array $anrInstanceMetadataFieldOldIdsToNewObjects + ): void { + foreach ($sourceInstance->getInstanceMetadata() as $sourceInstanceMetadata) { + $anrInstanceMetadataField = $anrInstanceMetadataFieldOldIdsToNewObjects[ + $sourceInstanceMetadata->getAnrInstanceMetadataField()->getId() + ]; + if ($anrInstanceMetadataField !== null) { + $instanceMetadata = (new Entity\InstanceMetadata()) + ->setInstance($newInstance) + ->setAnrInstanceMetadataField($anrInstanceMetadataField) + ->setComment($sourceInstanceMetadata->getComment()) + ->setCreator($this->connectedUser->getEmail()); + $this->instanceMetadataTable->save($instanceMetadata, false); } } + } - //objects - if ($model->get('anr')) { - $objects = $this->get('MonarcObjectTable')->fetchAllObject(); - foreach ($objects as $key => $object) { - $existInAnr = false; - foreach ($object->anrs as $anrObject) { - if ($anrObject->id == $model->get('anr')->get('id')) { - $existInAnr = true; - } - } - if (!$existInAnr) { - unset($objects[$key]); - } + private function duplicateSoasAndSoaScaleComments( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + array $createdMeasuresUuidsToObjects, + bool $isSourceCommon + ): void { + $commonTranslations = []; + if ($isSourceCommon) { + $commonTranslations = $this->coreTranslationTable->findByAnrTypesAndLanguageIndexedByKey( + $sourceAnr, + [CoreEntity\TranslationSuperClass::SOA_SCALE_COMMENT], + $newAnr->getLanguageCode() + ); + } + + $anrSoaScaleCommentOldIdsToNewObjects = []; + $soaScaleCommentTable = $isSourceCommon ? $this->coreSoaScaleCommentTable : $this->soaScaleCommentTable; + foreach ($soaScaleCommentTable->findByAnrOrderByIndex($sourceAnr) as $sourceSoaScaleComment) { + if ($isSourceCommon) { + /** @var CoreEntity\SoaScaleComment $sourceSoaScaleComment */ + $comment = isset($commonTranslations[$sourceSoaScaleComment->getLabelTranslationKey()]) + ? $commonTranslations[$sourceSoaScaleComment->getLabelTranslationKey()]->getValue() + : ''; + } else { + /** @var Entity\SoaScaleComment $sourceSoaScaleComment */ + $comment = $sourceSoaScaleComment->getComment(); } - foreach ($objects as $object) { - foreach ($languages as $lang) { - if (empty($object->getLabel($lang)) - || empty($object->getName($lang)) - || ($object->getCategory() !== null - && empty($object->getCategory()->getLabel($lang)) - ) - ) { - $success[$lang] = false; - } - } + $anrSoaScaleCommentOldIdsToNewObjects[$sourceSoaScaleComment->getId()] = $this->soaScaleCommentService + ->createSoaScaleComment( + $newAnr, + $sourceSoaScaleComment->getScaleIndex(), + $sourceSoaScaleComment->getColour(), + $comment, + $sourceSoaScaleComment->isHidden() + ); + } + + if ($isSourceCommon) { + foreach ($createdMeasuresUuidsToObjects as $measure) { + $this->soaTable->save((new Entity\Soa())->setAnr($newAnr)->setMeasure($measure), false); } } else { - foreach ($languages as $lang) { - $success[$lang] = false; + /** @var Entity\Soa $sourceSoa */ + foreach ($this->soaTable->findByAnr($sourceAnr) as $sourceSoa) { + $measure = $createdMeasuresUuidsToObjects[$sourceSoa->getMeasure()->getUuid()] ?? null; + if ($measure === null) { + continue; + } + $newSoa = (new Entity\Soa()) + ->setAnr($newAnr) + ->setMeasure($measure); + if ($sourceSoa->getSoaScaleComment() !== null) { + $newSoa->setSoaScaleComment( + $anrSoaScaleCommentOldIdsToNewObjects[$sourceSoa->getSoaScaleComment()->getId()] + ); + } + $this->soaTable->save($newSoa, false); } } - - return $success; } - private function createScalesFromSourceAnr( - Anr $newAnr, - AnrSuperClass $sourceAnr, - string $sourceName, - UserSuperClass $connectedUser + private function duplicateObjectsAndCategories( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + array $assetsOldIdsToNewObjects, + array $rolfTagsOldIdsToNewObjects, + bool $isSourceCommon ): array { - $scalesImpactTypesOldIdsToNewObjectsMap = []; - /** @var ScaleTable $scaleCliTable */ - $scaleCliTable = $this->get('scaleCliTable'); - /** @var ScaleTable|CoreScaleTable $scaleTable */ - $scaleTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('scaleTable') - : $scaleCliTable; - /** @var ScaleImpactTypeTable $scaleImpactTypeCliTable */ - $scaleImpactTypeCliTable = $this->get('scaleImpactTypeCliTable'); - - $scales = $scaleTable->findByAnr($sourceAnr); - foreach ($scales as $scale) { - $newScale = (new Scale()) - ->setAnr($newAnr) - ->setType($scale->getType()) - ->setMin($scale->getMin()) - ->setMax($scale->getMax()) - ->setCreator($connectedUser->getFirstname() . ' ' . $connectedUser->getLastname()); - - $scaleCliTable->saveEntity($newScale, false); - - foreach ($scale->getScaleImpactTypes() as $scaleImpactType) { - $newScaleImpactType = (new ScaleImpactType()) - ->setAnr($newAnr) - ->setScale($newScale) - ->setIsHidden($scaleImpactType->isHidden()) - ->setIsSys($scaleImpactType->isSys()) - ->setLabels([ - 'label1' => $scaleImpactType->getLabel(1), - 'label2' => $scaleImpactType->getLabel(2), - 'label3' => $scaleImpactType->getLabel(3), - 'label4' => $scaleImpactType->getLabel(4), - ]) - ->setType($scaleImpactType->getType()) - ->setPosition($scaleImpactType->getPosition()) - ->setCreator($connectedUser->getFirstname() . ' ' . $connectedUser->getLastname()); - - $scaleImpactTypeCliTable->saveEntity($newScaleImpactType, false); - - $scalesImpactTypesOldIdsToNewObjectsMap[$scaleImpactType->getId()] = $newScaleImpactType; - - foreach ($scaleImpactType->getScaleComments() as $scaleComment) { - $this->createScaleCommentsFromSource( + /** @var CoreEntity\ObjectSuperClass[] $sourceObjects */ + $sourceObjects = $isSourceCommon ? $sourceAnr->getObjects() : $this->monarcObjectTable->findByAnr($sourceAnr); + $objectCategoryOldIdsToNewObjects = []; + $monarcObjectsUuidsToNewObjects = []; + foreach ($sourceObjects as $sourceObject) { + $newObjectCategory = null; + if ($sourceObject->getCategory() !== null) { + if (!isset($objectCategoryOldIdsToNewObjects[$sourceObject->getCategory()->getId()])) { + $objectCategoryOldIdsToNewObjects = $this->duplicateObjectCategoryAndItsParents( $newAnr, - $newScale, - $newScaleImpactType, - $scaleComment, - $connectedUser + $sourceObject->getCategory(), + $objectCategoryOldIdsToNewObjects ); } + $newObjectCategory = $objectCategoryOldIdsToNewObjects[$sourceObject->getCategory()->getId()]; } - - foreach ($scale->getScaleComments() as $scaleComment) { - if ($scaleComment->getScaleImpactType() === null) { - $this->createScaleCommentsFromSource($newAnr, $newScale, null, $scaleComment, $connectedUser); - } + $rolfTag = null; + if ($sourceObject->getRolfTag() !== null) { + $rolfTag = $rolfTagsOldIdsToNewObjects[$sourceObject->getRolfTag()->getId()] ?? null; } + + $sourceUuid = $sourceObject->getUuid(); + $monarcObjectsUuidsToNewObjects[$sourceUuid] = $this->anrObjectService->createMonarcObject( + $newAnr, + $assetsOldIdsToNewObjects[$sourceObject->getAsset()->getUuid()], + $newObjectCategory, + $rolfTag, + array_merge([ + 'uuid' => $sourceUuid, + 'scope' => $sourceObject->getScope(), + 'setOnlyExactPosition' => true, + ], $sourceObject->getLabels(), $sourceObject->getNames()), + false + ); } - return $scalesImpactTypesOldIdsToNewObjectsMap; + /* Recreate the object's composition links. */ + foreach ($sourceObjects as $sourceObject) { + $this->duplicateObjectsCompositions($newAnr, $sourceObject, $monarcObjectsUuidsToNewObjects); + } + + return $monarcObjectsUuidsToNewObjects; } - private function createScaleCommentsFromSource( - Anr $newAnr, - ScaleSuperClass $newScale, - ?ScaleImpactTypeSuperClass $newScaleImpactType, - ScaleCommentSuperClass $sourceScaleComment, - UserSuperClass $connectedUser + private function duplicateObjectsCompositions( + Entity\Anr $newAnr, + CoreEntity\ObjectSuperClass $sourceObject, + array $monarcObjectsUuidsToNewObjects ): void { - /** @var ScaleCommentTable $scaleCommentCliTable */ - $scaleCommentCliTable = $this->get('scaleCommentCliTable'); - - $newScaleComment = (new ScaleComment()) - ->setAnr($newAnr) - ->setScale($newScale) - ->setScaleIndex($sourceScaleComment->getScaleIndex()) - ->setScaleValue($sourceScaleComment->getScaleValue()) - ->setComments([ - 'comment1' => $sourceScaleComment->getComment(1), - 'comment2' => $sourceScaleComment->getComment(2), - 'comment3' => $sourceScaleComment->getComment(3), - 'comment4' => $sourceScaleComment->getComment(4), - ]) - ->setCreator($connectedUser->getFirstname() . ' ' . $connectedUser->getLastname()); - if ($newScaleImpactType !== null) { - $newScaleComment->setScaleImpactType($newScaleImpactType); + foreach ($sourceObject->getChildrenLinks() as $sourceChildLinkObject) { + $newObjectObject = (new Entity\ObjectObject()) + ->setAnr($newAnr) + ->setParent($monarcObjectsUuidsToNewObjects[$sourceObject->getUuid()]) + ->setChild($monarcObjectsUuidsToNewObjects[$sourceChildLinkObject->getChild()->getUuid()]) + ->setPosition($sourceChildLinkObject->getPosition()) + ->setCreator($this->connectedUser->getEmail()); + $this->objectObjectTable->save($newObjectObject, false); } - - $scaleCommentCliTable->saveEntity($newScaleComment, false); } - private function createOperationalRiskScalesFromSourceAnr( - Anr $newAnr, - AnrSuperClass $sourceAnr, - string $sourceName, - UserSuperClass $connectedUser + private function duplicateObjectCategoryAndItsParents( + Entity\Anr $newAnr, + CoreEntity\ObjectCategorySuperClass $sourceObjectCategory, + array $objectCategoryOldIdsToNewObjects ): array { - $operationalScaleTypesOldIdsToNewObjectsMap = []; - /** @var OperationalRiskScaleTable $operationalRiskScaleCliTable */ - $operationalRiskScaleCliTable = $this->get('operationalRiskScaleCliTable'); - /** @var OperationalRiskScaleTable|CoreOperationalRiskScaleTable $sourceOperationalRiskScaleTable */ - $sourceOperationalRiskScaleTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('operationalRiskScaleTable') - : $operationalRiskScaleCliTable; - /** @var OperationalRiskScaleTypeTable $operationalRiskScaleTypeCliTable */ - $operationalRiskScaleTypeCliTable = $this->get('operationalRiskScaleTypeCliTable'); - /** @var TranslationTable|CoreTranslationTable $sourceTranslationTable */ - $sourceTranslationTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('translationTable') - : $this->get('translationCliTable'); - - $anrLanguageCode = $this->getAnrLanguageCode($newAnr); - - $sourceTranslations = $sourceTranslationTable->findByAnrTypesAndLanguageIndexedByKey( - $sourceAnr, - [Translation::OPERATIONAL_RISK_SCALE_TYPE, Translation::OPERATIONAL_RISK_SCALE_COMMENT], - $anrLanguageCode + /* Recreate parents recursively. */ + if ($sourceObjectCategory->getParent() !== null + && !isset($objectCategoryOldIdsToNewObjects[$sourceObjectCategory->getParent()->getId()]) + ) { + $objectCategoryOldIdsToNewObjects += $this->duplicateObjectCategoryAndItsParents( + $newAnr, + $sourceObjectCategory->getParent(), + $objectCategoryOldIdsToNewObjects + ); + } + + $objectCategoryOldIdsToNewObjects[$sourceObjectCategory->getId()] = $this->anrObjectCategoryService->create( + $newAnr, + array_merge([ + 'parent' => $sourceObjectCategory->getParent() !== null + ? $objectCategoryOldIdsToNewObjects[$sourceObjectCategory->getParent()->getId()] + : null, + 'setOnlyExactPosition' => true, + 'position' => $sourceObjectCategory->getPosition(), + ], $sourceObjectCategory->getLabels()), + false ); - $operationalRiskScales = $sourceOperationalRiskScaleTable->findByAnr($sourceAnr); - foreach ($operationalRiskScales as $operationalRiskScale) { - $newOperationalRiskScale = (new OperationalRiskScale()) - ->setAnr($newAnr) - ->setType($operationalRiskScale->getType()) - ->setMin($operationalRiskScale->getMin()) - ->setMax($operationalRiskScale->getMax()) - ->setCreator($connectedUser->getEmail()); + return $objectCategoryOldIdsToNewObjects; + } - foreach ($operationalRiskScale->getOperationalRiskScaleTypes() as $operationalRiskScaleType) { - $newOperationalRiskScaleType = (new OperationalRiskScaleType()) - ->setAnr($newAnr) - ->setOperationalRiskScale($newOperationalRiskScale) - ->setLabelTranslationKey($operationalRiskScaleType->getLabelTranslationKey()) - ->setIsHidden($operationalRiskScaleType->isHidden()) - ->setCreator($connectedUser->getEmail()); + private function duplicateInstancesTreeRisksSequencesRecommendationsMetadataAndScales( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + array $amvsOldIdsToNewObjects, + array $assetsOldIdsToNewObjects, + array $threatsOldIdsToNewObjects, + array $vulnerabilitiesOldIdsToNewObjects, + array $monarcObjectsOldIdsToNewObjects, + array $anrInstanceMetadataFieldOldIdsToNewObjects, + array $rolfRisksOldIdsToNewObjects, + bool $isSourceCommon + ): void { + /* Recreate Scales, ScalesComments and ScalesImpactTypes. */ + $scalesImpactTypesOldIdsToNewObjects = $this->duplicateScales($sourceAnr, $newAnr, $isSourceCommon); - $operationalRiskScaleTypeCliTable->save($newOperationalRiskScaleType, false); + /* Recreate Operational risks Scales, ScalesComments and ScalesTypes. */ + $operationalScaleTypesOldIdsToNewObjects = $this->duplicateOperationalRiskScales( + $sourceAnr, + $newAnr, + $isSourceCommon + ); - $operationalScaleTypesOldIdsToNewObjectsMap[$operationalRiskScaleType->getId()] - = $newOperationalRiskScaleType; + if (!$isSourceCommon) { + /** @var Entity\Anr $sourceAnr */ + $recommendationsUuidsToNewObjects = $this->duplicateRecommendationsAndSets($sourceAnr, $newAnr); + } - $this->createTranslationFromSource( - $newAnr, - $sourceTranslations[$operationalRiskScaleType->getLabelTranslationKey()] - ?? (new Translation()) - ->setType(Translation::OPERATIONAL_RISK_SCALE_TYPE) - ->setKey($operationalRiskScaleType->getLabelTranslationKey()) - ->setLang($anrLanguageCode) - ->setValue(''), - $connectedUser + $instancesOldIdsToNewObjects = []; + $instanceRisksOldIdsToNewObjects = []; + $instanceRisksOpOldIdsToNewObjects = []; + foreach ($sourceAnr->getInstances() as $sourceInstance) { + /** @var Entity\Instance $newInstance */ + $newInstance = Entity\Instance::constructFromObject($sourceInstance) + ->setAnr($newAnr) + ->setAsset($assetsOldIdsToNewObjects[$sourceInstance->getAsset()->getUuid()]) + ->setObject($monarcObjectsOldIdsToNewObjects[$sourceInstance->getObject()->getUuid()]) + ->setCreator($this->connectedUser->getEmail()); + if (!$isSourceCommon) { + $this->duplicateInstanceMetadata( + $sourceInstance, + $newInstance, + $anrInstanceMetadataFieldOldIdsToNewObjects ); + } - foreach ($operationalRiskScaleType->getOperationalRiskScaleComments() as $operationalRiskScaleComment) { - $this->createOperationalRiskScaleCommentsFromSource( - $newAnr, - $newOperationalRiskScale, - $newOperationalRiskScaleType, - $operationalRiskScaleComment, - $sourceTranslations[$operationalRiskScaleComment->getCommentTranslationKey()] - ?? (new Translation()) - ->setType(Translation::OPERATIONAL_RISK_SCALE_COMMENT) - ->setKey($operationalRiskScaleComment->getCommentTranslationKey()) - ->setLang($anrLanguageCode) - ->setValue(''), - $connectedUser - ); + $this->instanceTable->save($newInstance, false); + $instancesOldIdsToNewObjects[$sourceInstance->getId()] = $newInstance; + + /* Recreate InstanceRisks. */ + $instanceRisksOldIdsToNewObjects += $this->duplicateInstanceRisks( + $sourceInstance, + $newInstance, + $amvsOldIdsToNewObjects, + $assetsOldIdsToNewObjects, + $threatsOldIdsToNewObjects, + $vulnerabilitiesOldIdsToNewObjects + ); + + /* Recreate OperationalInstanceRisks. */ + $instanceRisksOpOldIdsToNewObjects += $this->duplicateOperationalInstanceRisks( + $sourceInstance, + $newInstance, + $rolfRisksOldIdsToNewObjects, + $operationalScaleTypesOldIdsToNewObjects + ); + + /* Recreate InstanceConsequences. */ + $this->duplicateInstanceConsequences($sourceInstance, $newInstance, $scalesImpactTypesOldIdsToNewObjects); + } + /* Recreate the hierarchy. */ + foreach ($sourceAnr->getInstances() as $sourceInstance) { + if ($sourceInstance->getRoot() || $sourceInstance->getParent()) { + $newInstance = $instancesOldIdsToNewObjects[$sourceInstance->getId()]; + if ($sourceInstance->getRoot()) { + $newInstance->setRoot($instancesOldIdsToNewObjects[$sourceInstance->getRoot()->getId()]); + } + if ($sourceInstance->getParent()) { + $newInstance->setParent($instancesOldIdsToNewObjects[$sourceInstance->getParent()->getId()]); } + $this->instanceTable->save($newInstance, false); } + } - foreach ($operationalRiskScale->getOperationalRiskScaleComments() as $operationalRiskScaleComment) { - if ($operationalRiskScaleComment->getOperationalRiskScaleType() !== null) { - continue; - } + if (!$isSourceCommon) { + /* Recreate RecommendationRisks and RecommendationsHistory. */ + $this->duplicateRecommendationsRisks( + $sourceAnr, + $recommendationsUuidsToNewObjects, + $instanceRisksOldIdsToNewObjects, + $instanceRisksOpOldIdsToNewObjects + ); + $this->duplicateRecommendationsHistory( + $sourceAnr, + $newAnr, + $instanceRisksOldIdsToNewObjects, + $instanceRisksOpOldIdsToNewObjects + ); + } + } - $this->createOperationalRiskScaleCommentsFromSource( + private function duplicateRecommendationsAndSets(Entity\Anr $sourceAnr, Entity\Anr $newAnr): array + { + $recommendationsUuidsToNewObjects = []; + foreach ($sourceAnr->getRecommendationSets() as $sourceRecommendationSet) { + $newRecommendationSet = $this->anrRecommendationSetService->create($newAnr, [ + 'uuid' => $sourceRecommendationSet->getUuid(), + 'label' => $sourceRecommendationSet->getLabel(), + ], false); + foreach ($sourceRecommendationSet->getRecommendations() as $sourceRecommendation) { + $recommendationUuid = $sourceRecommendation->getUuid(); + $recommendationsUuidsToNewObjects[$recommendationUuid] = $this->anrRecommendationService->create( $newAnr, - $newOperationalRiskScale, - null, - $operationalRiskScaleComment, - $sourceTranslations[$operationalRiskScaleComment->getCommentTranslationKey()] - ?? (new Translation()) - ->setType(Translation::OPERATIONAL_RISK_SCALE_COMMENT) - ->setKey($operationalRiskScaleComment->getCommentTranslationKey()) - ->setLang($anrLanguageCode) - ->setValue(''), - $connectedUser + [ + 'uuid' => $recommendationUuid, + 'recommendationSet' => $newRecommendationSet, + 'code' => $sourceRecommendation->getCode(), + 'description' => $sourceRecommendation->getDescription(), + 'importance' => $sourceRecommendation->getImportance(), + 'position' => $sourceRecommendation->getPosition(), + 'comment' => $sourceRecommendation->getComment(), + 'status' => $sourceRecommendation->getStatus(), + 'responsible' => $sourceRecommendation->getResponsible(), + 'duedate' => $sourceRecommendation->getDueDate(), + 'counterTreated' => $sourceRecommendation->getCounterTreated(), + ], + false ); } - - $operationalRiskScaleCliTable->save($newOperationalRiskScale, false); } - return $operationalScaleTypesOldIdsToNewObjectsMap; + return $recommendationsUuidsToNewObjects; } - private function createOperationalRiskScaleCommentsFromSource( - Anr $newAnr, - OperationalRiskScaleSuperClass $newOperationalRiskScale, - ?OperationalRiskScaleTypeSuperClass $newOperationalRiskScaleType, - OperationalRiskScaleCommentSuperClass $sourceOperationalRiskScaleComment, - TranslationSuperClass $sourceTranslation, - UserSuperClass $connectedUser - ): void { - /** @var OperationalRiskScaleCommentTable $operationalRiskScaleCommentCliTable */ - $operationalRiskScaleCommentCliTable = $this->get('operationalRiskScaleCommentCliTable'); + private function duplicateRecommendationsHistory( + Entity\Anr $sourceAnr, + Entity\Anr $newAnr, + array $instanceRisksOldIdsToNewObjects, + array $instanceRisksOpOldIdsToNewObjects, + ) { + /** @var Entity\RecommendationHistory $sourceRecommendationHistory */ + foreach ($this->recommendationHistoryTable->findByAnr($sourceAnr) as $sourceRecommendationHistory) { + $newRecommendationHistory = Entity\RecommendationHistory::constructFromObject($sourceRecommendationHistory) + ->setAnr($newAnr); + if ($sourceRecommendationHistory->getInstanceRisk() !== null + && isset($instanceRisksOldIdsToNewObjects[$sourceRecommendationHistory->getInstanceRisk()->getId()]) + ) { + $newRecommendationHistory->setInstanceRisk( + $instanceRisksOldIdsToNewObjects[$sourceRecommendationHistory->getInstanceRisk()->getId()] + ); + } elseif ($sourceRecommendationHistory->getInstanceRiskOp() !== null + && isset($instanceRisksOpOldIdsToNewObjects[$sourceRecommendationHistory->getInstanceRiskOp()->getId()]) + ) { + $newRecommendationHistory->setInstanceRiskOp( + $instanceRisksOpOldIdsToNewObjects[$sourceRecommendationHistory->getInstanceRiskOp()->getId()] + ); + } + $this->recommendationHistoryTable->save($newRecommendationHistory, false); + } + } - $newOperationalRiskScaleComment = (new OperationalRiskScaleComment()) - ->setAnr($newAnr) - ->setScaleIndex($sourceOperationalRiskScaleComment->getScaleIndex()) - ->setScaleValue($sourceOperationalRiskScaleComment->getScaleValue()) - ->setCommentTranslationKey($sourceOperationalRiskScaleComment->getCommentTranslationKey()) - ->setOperationalRiskScale($newOperationalRiskScale) - ->setIsHidden($sourceOperationalRiskScaleComment->isHidden()) - ->setCreator($connectedUser->getEmail()); - if ($newOperationalRiskScaleType !== null) { - $newOperationalRiskScaleComment->setOperationalRiskScaleType($newOperationalRiskScaleType); + private function duplicateRecommendationsRisks( + Entity\Anr $sourceAnr, + array $recommendationsUuidsToNewObjects, + array $instanceRisksOldIdsToNewObjects, + array $instanceRisksOpOldIdsToNewObjects, + ): void { + /* Recreate recommendations <-> risks relations. */ + /** @var Entity\RecommendationRisk $sourceRecommendationRisk */ + foreach ($this->recommendationRiskTable->findByAnr($sourceAnr) as $sourceRecommendationRisk) { + /** @var Entity\Recommendation $newRecommendation */ + $newRecommendation = $recommendationsUuidsToNewObjects[ + $sourceRecommendationRisk->getRecommendation()->getUuid() + ]; + /** @var Entity\InstanceRisk|Entity\InstanceRiskOp $newInstanceRisk */ + $newInstanceRisk = $sourceRecommendationRisk->getInstanceRisk() !== null + ? $instanceRisksOldIdsToNewObjects[$sourceRecommendationRisk->getInstanceRisk()->getId()] + : $instanceRisksOpOldIdsToNewObjects[$sourceRecommendationRisk->getInstanceRiskOp()->getId()]; + + $this->anrRecommendationRiskService->createRecommendationRisk( + $newRecommendation, + $newInstanceRisk, + $sourceRecommendationRisk->getCommentAfter(), + false + ); } + } + + private function duplicateInstanceRisks( + CoreEntity\InstanceSuperClass $sourceInstance, + Entity\Instance $newInstance, + array $amvsOldIdsToNewObjects, + array $assetsOldIdsToNewObjects, + array $threatsOldIdsToNewObjects, + array $vulnerabilitiesOldIdsToNewObjects + ): array { + /** @var Entity\Anr $newAnr */ + $newAnr = $newInstance->getAnr(); + $instancesRisksOldIdsToNewObjects = []; + foreach ($sourceInstance->getInstanceRisks() as $sourceInstanceRisk) { + /** @var Entity\InstanceRisk $newInstanceRisk */ + $newInstanceRisk = Entity\InstanceRisk::constructFromObject($sourceInstanceRisk) + ->setAnr($newAnr) + ->setInstance($newInstance) + ->setCreator($this->connectedUser->getEmail()); + if ($sourceInstanceRisk->getAmv() !== null) { + $newInstanceRisk->setAmv($amvsOldIdsToNewObjects[$sourceInstanceRisk->getAmv()->getUuid()]); + } + if ($sourceInstanceRisk->getAsset() !== null) { + $newInstanceRisk->setAsset($assetsOldIdsToNewObjects[$sourceInstanceRisk->getAsset()->getUuid()]); + } + if ($sourceInstanceRisk->getThreat() !== null) { + $newInstanceRisk->setThreat($threatsOldIdsToNewObjects[$sourceInstanceRisk->getThreat()->getUuid()]); + } + if ($sourceInstanceRisk->getVulnerability() !== null) { + $newInstanceRisk->setVulnerability( + $vulnerabilitiesOldIdsToNewObjects[$sourceInstanceRisk->getVulnerability()->getUuid()] + ); + } + if ($sourceInstanceRisk instanceof Entity\InstanceRisk + && $sourceInstanceRisk->getInstanceRiskOwner() !== null + ) { + /** @var Entity\Anr $sourceAnr */ + $sourceAnr = $sourceInstance->getAnr(); + $newInstanceRisk->setInstanceRiskOwner($this->instanceRiskOwnerService->getOrCreateInstanceRiskOwner( + $sourceAnr, + $newAnr, + $sourceInstanceRisk->getInstanceRiskOwner()->getName(), + )); + } - $operationalRiskScaleCommentCliTable->save($newOperationalRiskScaleComment, false); + $this->instanceRiskTable->save($newInstanceRisk, false); + $instancesRisksOldIdsToNewObjects[$sourceInstanceRisk->getId()] = $newInstanceRisk; + } - $this->createTranslationFromSource($newAnr, $sourceTranslation, $connectedUser); + return $instancesRisksOldIdsToNewObjects; } - private function createTranslationFromSource( - Anr $newAnr, - TranslationSuperClass $sourceTranslation, - UserSuperClass $connectedUser - ): void { - /** @var TranslationTable $translationCliTable */ - $translationCliTable = $this->get('translationCliTable'); + private function duplicateOperationalInstanceRisks( + CoreEntity\InstanceSuperClass $sourceInstance, + Entity\Instance $newInstance, + array $rolfRisksOldIdsToNewObjects, + array $operationalScaleTypesOldIdsToNewObjects + ): array { + /** @var Entity\Anr $newAnr */ + $newAnr = $newInstance->getAnr(); + $instancesRisksOpOldIdsToNewObjects = []; + foreach ($sourceInstance->getOperationalInstanceRisks() as $sourceInstanceRiskOp) { + /** @var Entity\InstanceRiskOp $newInstanceRiskOp */ + $newInstanceRiskOp = Entity\InstanceRiskOp::constructFromObject($sourceInstanceRiskOp) + ->setAnr($newAnr) + ->setInstance($newInstance) + ->setObject($newInstance->getObject()) + ->setCreator($this->connectedUser->getEmail()); + if ($sourceInstanceRiskOp->getRolfRisk() !== null) { + $newInstanceRiskOp->setRolfRisk( + $rolfRisksOldIdsToNewObjects[$sourceInstanceRiskOp->getRolfRisk()->getId()] + ); + } + if ($sourceInstanceRiskOp instanceof Entity\InstanceRiskOp + && $sourceInstanceRiskOp->getInstanceRiskOwner() !== null + ) { + /** @var Entity\Anr $sourceAnr */ + $sourceAnr = $sourceInstance->getAnr(); + $instanceRiskOwner = $this->instanceRiskOwnerService->getOrCreateInstanceRiskOwner( + $sourceAnr, + $newAnr, + $sourceInstanceRiskOp->getInstanceRiskOwner()->getName(), + ); + $newInstanceRiskOp->setInstanceRiskOwner($instanceRiskOwner); + } - $newTranslation = (new Translation()) - ->setAnr($newAnr) - ->setType($sourceTranslation->getType()) - ->setKey($sourceTranslation->getKey()) - ->setLang($sourceTranslation->getLang()) - ->setValue($sourceTranslation->getValue()) - ->setCreator($connectedUser->getEmail()); + $this->instanceRiskOpTable->save($newInstanceRiskOp, false); + + $this->duplicateOperationalInstanceRiskScales( + $sourceInstanceRiskOp, + $newInstanceRiskOp, + $newAnr, + $operationalScaleTypesOldIdsToNewObjects + ); + + $instancesRisksOpOldIdsToNewObjects[$sourceInstanceRiskOp->getId()] = $newInstanceRiskOp; + } - $translationCliTable->save($newTranslation, false); + return $instancesRisksOpOldIdsToNewObjects; } - private function createOperationalInstanceRiskScalesFromSource( - InstanceRiskOpSuperClass $instanceRiskOp, - array $operationalScaleTypesOldIdsToNewObjectsMap, - Anr $newAnr, - InstanceRiskOp $newInstanceRiskOp, - UserSuperClass $connectedUser + private function duplicateOperationalInstanceRiskScales( + CoreEntity\InstanceRiskOpSuperClass $sourceInstanceRiskOp, + Entity\InstanceRiskOp $newInstanceRiskOp, + Entity\Anr $newAnr, + array $operationalScaleTypesOldIdsToNewObjectsMap ): void { - /** @var OperationalInstanceRiskScaleTable $operationalInstanceRiskScaleCliTable */ - $operationalInstanceRiskScaleCliTable = $this->get('operationalInstanceRiskScaleCliTable'); - foreach ($instanceRiskOp->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { + foreach ($sourceInstanceRiskOp->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { $operationalRiskScaleType = $operationalScaleTypesOldIdsToNewObjectsMap[ $operationalInstanceRiskScale->getOperationalRiskScaleType()->getId() ]; - $operationalInstanceRiskScale = (new OperationalInstanceRiskScale()) + $operationalInstanceRiskScale = (new Entity\OperationalInstanceRiskScale()) ->setAnr($newAnr) ->setOperationalInstanceRisk($newInstanceRiskOp) ->setOperationalRiskScaleType($operationalRiskScaleType) ->setBrutValue($operationalInstanceRiskScale->getBrutValue()) ->setNetValue($operationalInstanceRiskScale->getNetValue()) ->setTargetedValue($operationalInstanceRiskScale->getTargetedValue()) - ->setCreator($connectedUser->getEmail()); - $operationalInstanceRiskScaleCliTable->save($operationalInstanceRiskScale, false); + ->setCreator($this->connectedUser->getEmail()); + $this->operationalInstanceRiskScaleTable->save($operationalInstanceRiskScale, false); } } - private function getOrCreateInstanceRiskOwner( - AnrSuperClass $anr, - string $ownerName, - UserSuperClass $connectedUser - ): InstanceRiskOwner { - if (!isset($this->cachedData['instanceRiskOwners'][$ownerName])) { - /** @var InstanceRiskOwnerTable $instanceRiskOwnerTable */ - $instanceRiskOwnerTable = $this->get('instanceRiskOwnerCliTable'); - $instanceRiskOwner = $instanceRiskOwnerTable->findByAnrAndName($anr, $ownerName); - if ($instanceRiskOwner === null) { - $instanceRiskOwner = (new InstanceRiskOwner()) - ->setAnr($anr) - ->setName($ownerName) - ->setCreator($connectedUser->getEmail()); - - $instanceRiskOwnerTable->save($instanceRiskOwner, false); - } - - $this->cachedData['instanceRiskOwners'][$ownerName] = $instanceRiskOwner; + private function duplicateInstanceConsequences( + CoreEntity\InstanceSuperClass $sourceInstance, + Entity\Instance $newInstance, + array $scalesImpactTypesOldIdsToNewObjects + ): void { + foreach ($sourceInstance->getInstanceConsequences() as $sourceInstanceConsequence) { + $newInstanceConsequence = Entity\InstanceConsequence::constructFromObject($sourceInstanceConsequence) + ->setAnr($newInstance->getAnr()) + ->setInstance($newInstance) + ->setScaleImpactType( + $scalesImpactTypesOldIdsToNewObjects[$sourceInstanceConsequence->getScaleImpactType()->getId()] + ) + ->setCreator($this->connectedUser->getEmail()); + $this->instanceConsequenceTable->save($newInstanceConsequence, false); } + } - return $this->cachedData['instanceRiskOwners'][$ownerName]; + private function duplicateQuestions( + CoreEntity\AnrSuperClass $sourceAnr, + Entity\Anr $newAnr, + bool $isSourceCommon + ): void { + /** @var CoreEntity\QuestionSuperClass[] $questions */ + $questions = $isSourceCommon + ? $this->coreQuestionTable->fetchAllObject() + : $this->questionTable->findByAnr($sourceAnr); + $questionsNewIds = []; + foreach ($questions as $q) { + $newQuestion = new Entity\Question($q); + $newQuestion->setId(null); + $newQuestion->setAnr($newAnr); + $this->questionTable->save($newQuestion, false); + $questionsNewIds[$q->getId()] = $newQuestion; + } + /** @var CoreEntity\QuestionChoiceSuperClass[] $questionChoices */ + $questionChoices = $isSourceCommon + ? $this->coreQuestionChoiceTable->fetchAllObject() + : $this->questionChoiceTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + foreach ($questionChoices as $qc) { + $newQuestionChoice = new Entity\QuestionChoice($qc); + $newQuestionChoice->setId(null); + $newQuestionChoice->setAnr($newAnr); + $newQuestionChoice->setQuestion($questionsNewIds[$qc->getQuestion()->getId()]); + $this->questionChoiceTable->save($newQuestionChoice, false); + } } - private function getAnrLanguageCode(AnrSuperClass $anr): string + private function duplicateInterviews(Entity\Anr $sourceAnr, Entity\Anr $newAnr): void { - /** @var ConfigService $configService */ - $configService = $this->get('configService'); - - return strtolower($configService->getLanguageCodes()[$anr->getLanguage()]); + $interviews = $this->interviewTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + foreach ($interviews as $interview) { + $newInterview = new Entity\Interview($interview); + $newInterview->set('id', null); + $newInterview->setAnr($newAnr); + $this->interviewTable->save($newInterview, false); + } } - private function createAnrMetadatasOnInstancesFromSource( - Anr $newAnr, - AnrSuperClass $sourceAnr, - string $sourceName, - UserSuperClass $connectedUser - ): array { - - $anrMetadatasOnInstancesOldIdsToNewObjectsMap = []; - - /** @var AnrMetadatasOnInstancesCliTable $anrMetadatasOnInstancesCliTable */ - $anrMetadatasOnInstancesCliTable = $this->get('anrMetadatasOnInstancesCliTable'); - - /** @var AnrMetadatasOnInstancesCliTable|CoreAnrMetadatasOnInstancesCliTable $scaleTable */ - $anrMetadatasOnInstancesTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('anrMetadatasOnInstancesTable') - : $anrMetadatasOnInstancesCliTable; - - /** @var TranslationTable|CoreTranslationTable $sourceTranslationTable */ - $sourceTranslationTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('translationTable') - : $this->get('translationCliTable'); - - $anrLanguageCode = $this->getAnrLanguageCode($newAnr); - - $oldAnrMetadatasOnInstances = $anrMetadatasOnInstancesTable->findByAnr($sourceAnr); - foreach ($oldAnrMetadatasOnInstances as $oldAnrMetadata) { - $newAnrMetadataOnInstance = (new AnrMetadatasOnInstances()) - ->setAnr($newAnr) - ->setLabelTranslationKey($oldAnrMetadata->getLabelTranslationKey()) - ->setIsDeletable($sourceName === MonarcObject::SOURCE_COMMON ? false : $oldAnrMetadata->isDeletable()) - ->setCreator($connectedUser->getEmail()); - $anrMetadatasOnInstancesCliTable->save($newAnrMetadataOnInstance, false); - $anrMetadatasOnInstancesOldIdsToNewObjectsMap[$oldAnrMetadata->getId()] = $newAnrMetadataOnInstance; + private function duplicateRopa(Entity\Anr $sourceAnr, Entity\Anr $newAnr): void + { + /* Recreate record actors. */ + $recordActors = $this->recordActorTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + $actorNewIds = []; + foreach ($recordActors as $a) { + $newActor = new Entity\RecordActor($a); + $newActor->set('id', null); + $newActor->setAnr($newAnr); + $this->recordActorTable->save($newActor, false); + $actorNewIds[$a->id] = $newActor; } - $sourceTranslations = $sourceTranslationTable->findByAnrTypesAndLanguageIndexedByKey( - $sourceAnr, - [Translation::ANR_METADATAS_ON_INSTANCES], - $anrLanguageCode - ); - - foreach ($sourceTranslations as $sourceTranslation) { - $this->createTranslationFromSource($newAnr, $sourceTranslation, $connectedUser); + /* Recreate record data categories. */ + $recordDataCategories = $this->recordDataCategoryTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + $dataCategoryNewIds = []; + foreach ($recordDataCategories as $dc) { + $newDataCategory = new Entity\RecordDataCategory($dc); + $newDataCategory->set('id', null); + $newDataCategory->setAnr($newAnr); + $this->recordDataCategoryTable->save($newDataCategory, true); + $dataCategoryNewIds[$dc->id] = $newDataCategory; } - return $anrMetadatasOnInstancesOldIdsToNewObjectsMap; - } - - private function createInstanceMetadatasFromSource( - UserSuperClass $connectedUser, - Instance $oldInstance, - Instance $instance, - Anr $sourceAnr, - Anr $newAnr, - array $anrMetadatasOnInstancesOldIdsToNewObjectsMap - ) :void { - $translations = []; - $anrLanguageCode = $this->getAnrLanguageCode($newAnr); - - $sourceTranslationTable = $this->get('translationCliTable'); - $oldInstanceMetadatas = $oldInstance->getInstanceMetadatas(); - foreach ($oldInstanceMetadatas as $oldInstanceMetadata) { - $translationKey = $oldInstanceMetadata->getCommentTranslationKey(); - $instanceMetada = (new InstanceMetadata()) - ->setInstance($instance) - ->setMetadata($anrMetadatasOnInstancesOldIdsToNewObjectsMap[ - $oldInstanceMetadata->getMetadata()->getId()]) - ->setCommentTranslationKey($translationKey) - ->setCreator($connectedUser->getEmail()); - - $this->get('instanceMetadataCliTable')->save($instanceMetada, false); - $instance->addInstanceMetadata($instanceMetada); - - $translations = $sourceTranslationTable->findByAnrTypesAndLanguageIndexedByKey( - $sourceAnr, - [Translation::INSTANCE_METADATA], - $anrLanguageCode - ); + /* Recreate record processors. */ + $recordProcessors = $this->recordProcessorTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + $processorNewIds = []; + foreach ($recordProcessors as $p) { + $newProcessor = new Entity\RecordProcessor($p); + $newProcessor->set('id', null); + $newProcessor->setAnr($newAnr); + $activities = []; + $newProcessor->setActivities($activities); + $secMeasures = []; + $newProcessor->setSecMeasures($secMeasures); + if ($p->representative != null) { + $newProcessor->setRepresentative($actorNewIds[$p->representative->id]); + } + if ($p->dpo != null) { + $newProcessor->setDpo($actorNewIds[$p->dpo->id]); + } + $this->recordProcessorTable->save($newProcessor, false); + $processorNewIds[$p->id] = $newProcessor; } - foreach ($translations as $translation) { - $this->createTranslationFromSource($newAnr, $translation, $connectedUser); + /* Recreate record recipients. */ + $recordRecipients = $this->recordRecipientTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + $recipientNewIds = []; + foreach ($recordRecipients as $r) { + $newRecipient = new Entity\RecordRecipient($r); + $newRecipient->set('id', null); + $newRecipient->setAnr($newAnr); + $this->recordRecipientTable->save($newRecipient, false); + $recipientNewIds[$r->id] = $newRecipient; } - } - - private function createSoaScaleCommentFromSource( - Anr $newAnr, - AnrSuperClass $sourceAnr, - string $sourceName, - UserSuperClass $connectedUser - ): array { - - $anrSoaScaleCommentOldIdsToNewObjectsMap = []; - /** @var SoaScaleCommentCliTable $soaScaleCommentCliTable */ - $soaScaleCommentCliTable = $this->get('soaScaleCommentCliTable'); + /* Recreate record. */ + $records = $this->recordTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + $recordNewIds = []; + foreach ($records as $record) { + $newRecord = new Entity\Record($record); + $newRecord->set('id', null); + $newRecord->setAnr($newAnr); + if ($record->controller != null) { + $newRecord->setController($actorNewIds[$record->controller->id]); + } + if ($record->representative != null) { + $newRecord->setRepresentative($actorNewIds[$record->representative->id]); + } + if ($record->dpo != null) { + $newRecord->setDpo($actorNewIds[$record->dpo->id]); + } - /** @var SoaScaleCommentCliTable|CoreSoaScaleCommentCliTable $scaleTable */ - $soaScaleCommentTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('soaScaleCommentTable') - : $soaScaleCommentCliTable; + $jointControllerNewIds = []; + $jointControllers = $record->getJointControllers(); + foreach ($jointControllers as $jc) { + $jointControllerNewIds[] = $actorNewIds[$jc->id]; + } + $newRecord->setJointControllers($jointControllerNewIds); - /** @var TranslationTable|CoreTranslationTable $sourceTranslationTable */ - $sourceTranslationTable = $sourceName === MonarcObject::SOURCE_COMMON - ? $this->get('translationTable') - : $this->get('translationCliTable'); + $processorIds = []; + $processors = $record->getProcessors(); + foreach ($processors as $p) { + $processorIds[] = $processorNewIds[$p->id]; + } + $newRecord->setProcessors($processorIds); - $anrLanguageCode = $this->getAnrLanguageCode($newAnr); + $recipientIds = []; + $recipients = $record->getRecipients(); + foreach ($recipients as $r) { + $recipientIds[$r->id] = $recipientNewIds[$r->id]; + } + $newRecord->setRecipients($recipientIds); - $oldSoaScaleComments = $soaScaleCommentTable->findByAnr($sourceAnr); - foreach ($oldSoaScaleComments as $oldSoaScaleComment) { - $newSoaScaleComment = (new SoaScaleComment()) - ->setAnr($newAnr) - ->setCommentTranslationKey($oldSoaScaleComment->getCommentTranslationKey()) - ->setScaleIndex($oldSoaScaleComment->getScaleIndex()) - ->setColour($oldSoaScaleComment->getColour()) - ->setIsHidden($oldSoaScaleComment->isHidden()) - ->setCreator($connectedUser->getEmail()); - $soaScaleCommentCliTable->save($newSoaScaleComment, false); - $anrSoaScaleCommentOldIdsToNewObjectsMap[$oldSoaScaleComment->getId()] = $newSoaScaleComment; + $this->recordTable->save($newRecord, false); + $recordNewIds[$record->id] = $newRecord; } - $sourceTranslations = $sourceTranslationTable->findByAnrTypesAndLanguageIndexedByKey( - $sourceAnr, - [Translation::SOA_SCALE_COMMENT], - $anrLanguageCode - ); + foreach ($recordProcessors as $p) { + $data = []; + $activities = $p->getActivities(); + foreach ($activities as $recordId => $value) { + $data["activities"][$recordNewIds[$recordId]->getId()] = $value; + } + $secMeasures = $p->getSecMeasures(); + foreach ($secMeasures as $recordId => $value) { + $data["secMeasures"][$recordNewIds[$recordId]->getId()] = $value; + } + $this->anrRecordProcessorService->patch($processorNewIds[$p->id]->getId(), $data); + } - foreach ($sourceTranslations as $sourceTranslation) { - $this->createTranslationFromSource($newAnr, $sourceTranslation, $connectedUser); + //duplicate record personal data + $recordPersonalData = $this->recordPersonalDataTable->getEntityByFields(['anr' => $sourceAnr->getId()]); + foreach ($recordPersonalData as $pd) { + $newPersonalData = new Entity\RecordPersonalData($pd); + $newPersonalData->set('id', null); + $newPersonalData->setAnr($newAnr); + $newPersonalData->setRecord($recordNewIds[$pd->record->id]); + $newDataCategoryIds = []; + $dataCategories = $pd->getDataCategories(); + foreach ($dataCategories as $dc) { + $newDataCategoryIds[] = $dataCategoryNewIds[$dc->id]; + } + $newPersonalData->setDataCategories($newDataCategoryIds); + $this->recordPersonalDataTable->save($newPersonalData, false); } - return $anrSoaScaleCommentOldIdsToNewObjectsMap; + /* Recreate record international transfers. */ + $recordInternationalTransfers = $this->recordInternationalTransferTable + ->getEntityByFields(['anr' => $sourceAnr->getId()]); + foreach ($recordInternationalTransfers as $it) { + $newInternationalTransfer = new Entity\RecordInternationalTransfer($it); + $newInternationalTransfer->set('id', null); + $newInternationalTransfer->setAnr($newAnr); + $newInternationalTransfer->setRecord($recordNewIds[$it->record->id]); + $this->recordInternationalTransferTable->save($newInternationalTransfer, false); + } } } diff --git a/src/Service/AnrServiceFactory.php b/src/Service/AnrServiceFactory.php deleted file mode 100755 index 497ea75b..00000000 --- a/src/Service/AnrServiceFactory.php +++ /dev/null @@ -1,128 +0,0 @@ - Anr::class, - 'table' => Table\AnrTable::class, - - //core - 'anrTable' => CoreTable\AnrTable::class, - 'amvTable' => CoreTable\AmvTable::class, - 'anrObjectCategoryTable' => CoreTable\AnrObjectCategoryTable::class, - 'assetTable' => CoreTable\AssetTable::class, - 'instanceTable' => CoreTable\InstanceTable::class, - 'instanceConsequenceTable' => CoreTable\InstanceConsequenceTable::class, - 'instanceRiskTable' => CoreTable\InstanceRiskTable::class, - 'instanceRiskOpTable' => CoreTable\InstanceRiskOpTable::class, - 'measureTable' => CoreTable\MeasureTable::class, - 'modelTable' => CoreTable\ModelTable::class, - 'MonarcObjectTable' => CoreTable\MonarcObjectTable::class, - 'objectCategoryTable' => CoreTable\ObjectCategoryTable::class, - 'objectObjectTable' => CoreTable\ObjectObjectTable::class, - 'rolfRiskTable' => CoreTable\RolfRiskTable::class, - 'rolfTagTable' => CoreTable\RolfTagTable::class, - 'scaleTable' => CoreTable\ScaleTable::class, - 'scaleCommentTable' => CoreTable\ScaleCommentTable::class, - 'scaleImpactTypeTable' => CoreTable\ScaleImpactTypeTable::class, - 'threatTable' => CoreTable\ThreatTable::class, - 'themeTable' => CoreTable\ThemeTable::class, - 'vulnerabilityTable' => CoreTable\VulnerabilityTable::class, - 'questionTable' => CoreTable\QuestionTable::class, - 'questionChoiceTable' => CoreTable\QuestionChoiceTable::class, - 'soaCategoryTable' => CoreTable\SoaCategoryTable::class, - 'referentialTable' => CoreTable\ReferentialTable::class, - 'operationalRiskScaleTable' => CoreTable\OperationalRiskScaleTable::class, - 'operationalRiskScaleCommentTable' => CoreTable\OperationalRiskScaleCommentTable::class, - 'translationTable' => CoreTable\TranslationTable::class, - 'anrMetadatasOnInstancesTable' => CoreTable\AnrMetadatasOnInstancesTable::class, - 'soaScaleCommentTable' => CoreTable\SoaScaleCommentTable::class, - - //fo - 'anrCliTable' => Table\AnrTable::class, - 'amvCliTable' => Table\AmvTable::class, - 'anrObjectCategoryCliTable' => Table\AnrObjectCategoryTable::class, - 'assetCliTable' => Table\AssetTable::class, - 'instanceCliTable' => Table\InstanceTable::class, - 'instanceConsequenceCliTable' => Table\InstanceConsequenceTable::class, - 'instanceRiskCliTable' => Table\InstanceRiskTable::class, - 'instanceRiskOpCliTable' => Table\InstanceRiskOpTable::class, - 'interviewCliTable' => Table\InterviewTable::class, - 'measureCliTable' => Table\MeasureTable::class, - 'objectCliTable' => Table\MonarcObjectTable::class, - 'objectCategoryCliTable' => Table\ObjectCategoryTable::class, - 'objectObjectCliTable' => Table\ObjectObjectTable::class, - 'recommendationTable' => Table\RecommandationTable::class, - 'recommandationHistoricCliTable' => Table\RecommendationHistoricTable::class, - 'recommandationRiskCliTable' => Table\RecommandationRiskTable::class, - 'recommandationSetCliTable' => Table\RecommandationSetTable::class, - 'rolfRiskCliTable' => Table\RolfRiskTable::class, - 'rolfTagCliTable' => Table\RolfTagTable::class, - 'scaleCliTable' => Table\ScaleTable::class, - 'scaleCommentCliTable' => Table\ScaleCommentTable::class, - 'scaleImpactTypeCliTable' => Table\ScaleImpactTypeTable::class, - 'snapshotCliTable' => Table\SnapshotTable::class, - 'threatCliTable' => Table\ThreatTable::class, - 'themeCliTable' => Table\ThemeTable::class, - 'userCliTable' => Table\UserTable::class, - 'userAnrCliTable' => Table\UserAnrTable::class, - 'vulnerabilityCliTable' => Table\VulnerabilityTable::class, - 'questionCliTable' => Table\QuestionTable::class, - 'questionChoiceCliTable' => Table\QuestionChoiceTable::class, - 'soaTable' => Table\SoaTable::class, - 'soaCategoryCliTable' => Table\SoaCategoryTable::class, - 'recordCliTable' => Table\RecordTable::class, - 'recordActorCliTable' => Table\RecordActorTable::class, - 'recordDataCategoryCliTable' => Table\RecordDataCategoryTable::class, - 'recordPersonalDataCliTable' => Table\RecordPersonalDataTable::class, - 'recordInternationalTransferCliTable' => Table\RecordInternationalTransferTable::class, - 'recordProcessorCliTable' => Table\RecordProcessorTable::class, - 'recordRecipientCliTable' => Table\RecordRecipientTable::class, - 'referentialCliTable' => Table\ReferentialTable::class, - 'measureMeasureCliTable' => Table\MeasureMeasureTable::class, - 'operationalRiskScaleCliTable' => Table\OperationalRiskScaleTable::class, - 'operationalRiskScaleTypeCliTable' => Table\OperationalRiskScaleTypeTable::class, - 'operationalRiskScaleCommentCliTable' => Table\OperationalRiskScaleCommentTable::class, - 'operationalInstanceRiskScaleCliTable' => Table\OperationalInstanceRiskScaleTable::class, - 'instanceRiskOwnerCliTable' => Table\InstanceRiskOwnerTable::class, - 'translationCliTable' => Table\TranslationTable::class, - 'anrMetadatasOnInstancesCliTable' => Table\AnrMetadatasOnInstancesTable::class, - 'instanceMetadataCliTable' => Table\InstanceMetadataTable::class, - 'soaScaleCommentCliTable' => Table\SoaScaleCommentTable::class, - - - // export - 'instanceService' => AnrInstanceService::class, - 'recordService' => AnrRecordService::class, - 'recordProcessorService' => AnrRecordProcessorService::class, - - // Stats Service - 'statsAnrService' => StatsAnrService::class, - - // other Service - 'configService' => ConfigService::class, - 'cronTaskService' => CronTaskService::class, - ]; -} diff --git a/src/Service/AnrThemeService.php b/src/Service/AnrThemeService.php index 83d2e6d5..75cf4f71 100755 --- a/src/Service/AnrThemeService.php +++ b/src/Service/AnrThemeService.php @@ -1,20 +1,86 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $params): array + { + $result = []; + /** @var Theme $theme */ + foreach ($this->themeTable->findByParams($params) as $theme) { + $result[] = $this->prepareThemeDataResult($theme); + } + + return $result; + } + + public function getThemeData(Anr $anr, int $id): array + { + /** @var Theme $theme */ + $theme = $this->themeTable->findByIdAndAnr($id, $anr); + + return $this->prepareThemeDataResult($theme); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): Theme + { + $theme = (new Theme()) + ->setAnr($anr) + ->setLabels($data) + ->setCreator($this->connectedUser->getEmail()); + + $this->themeTable->save($theme, $saveInDb); + + return $theme; + } + + public function update(Anr $anr, int $id, array $data): void + { + /** @var Theme $theme */ + $theme = $this->themeTable->findByIdAndAnr($id, $anr); + + $theme->setLabels($data) + ->setUpdater($this->connectedUser->getEmail()); + + $this->themeTable->save($theme); + } + + public function delete(Anr $anr, int $id): void + { + /** @var Theme $theme */ + $theme = $this->themeTable->findByIdAndAnr($id, $anr); + + $this->themeTable->remove($theme); + } + + private function prepareThemeDataResult(Theme $theme): array + { + return [ + 'id' => $theme->getId(), + 'label1' => $theme->getLabel(1), + 'label2' => $theme->getLabel(2), + 'label3' => $theme->getLabel(3), + 'label4' => $theme->getLabel(4), + ]; + } } diff --git a/src/Service/AnrThemeServiceFactory.php b/src/Service/AnrThemeServiceFactory.php deleted file mode 100755 index 30a6f984..00000000 --- a/src/Service/AnrThemeServiceFactory.php +++ /dev/null @@ -1,24 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Theme', - 'table' => 'Monarc\FrontOffice\Model\Table\ThemeTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - ]; -} diff --git a/src/Service/AnrThreatService.php b/src/Service/AnrThreatService.php index 74dd2a89..d00bf275 100755 --- a/src/Service/AnrThreatService.php +++ b/src/Service/AnrThreatService.php @@ -1,93 +1,247 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $params): array { - $this->manageQualification($id, $data); - return parent::update($id, $data); + $result = []; + + /** @var Threat $threat */ + foreach ($this->threatTable->findByParams($params) as $threat) { + $result[] = $this->prepareThreatDataResult($threat); + } + + return $result; } - /** - * @inheritdoc - */ - public function patch($id, $data) + public function getCount(FormattedInputParams $params): int { - $this->manageQualification($id, $data); - return parent::patch($id, $data); + return $this->threatTable->countByParams($params); } - /** - * Updates the qualifications for the specified threat whenever they are created or updated. This noticeably - * handles qualification values inheritance. - * - * @param int $id The threat ID - * @param array $data The qualification data - */ - public function manageQualification($id, $data) + public function getThreatData(Anr $anr, string $uuid): array { + /** @var Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($uuid, $anr); + + return $this->prepareThreatDataResult($threat); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): Threat + { + $threat = (new Threat()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setComment($threatData['comment'] ?? '') + ->setCreator($this->connectedUser->getEmail()); + if (isset($data['uuid'])) { + $threat->setUuid($data['uuid']); + } + if (isset($data['c'])) { + $threat->setConfidentiality((int)$data['c']); + } + if (isset($data['i'])) { + $threat->setIntegrity((int)$data['i']); + } + if (isset($data['a'])) { + $threat->setAvailability((int)$data['a']); + } + if (isset($data['mode'])) { + $threat->setMode((int)$data['mode']); + } + if (isset($data['status'])) { + $threat->setStatus($data['status']); + } + if (isset($data['trend'])) { + $threat->setTrend((int)$data['trend']); + } if (isset($data['qualification'])) { - $filter = [ - 'anr' => $data['anr'], - 'threat' => $id, - ]; - - // If qualification is not forced, retrieve only inherited instance risksx - if (empty($data['forceQualification'])) { - $filter['mh'] = 1; - } + $threat->setTrend((int)$data['qualification']); + } + + $this->validateCia($threat); - /** @var InstanceRiskTable $instanceRiskTable */ - $instanceRiskTable = $this->get('instanceRiskTable'); - $instancesRisks = $instanceRiskTable->getEntityByFields($filter); + if (!empty($data['theme'])) { + /** @var Theme $theme */ + $theme = $data['theme'] instanceof Theme + ? $data['theme'] + : $this->themeTable->findById((int)$data['theme']); + + $threat->setTheme($theme); + } - /** @var AnrInstanceRiskService $instanceRiskService */ - $instanceRiskService = $this->get('instanceRiskService'); + $this->threatTable->save($threat, $saveInDb); + + return $threat; + } + + public function createList(Anr $anr, array $data): array + { + $createdUuids = []; + foreach ($data as $row) { + $createdUuids[] = $this->create($anr, $row, false)->getUuid(); + } + $this->threatTable->flush(); + + return $createdUuids; + } + + public function update(Anr $anr, string $uuid, array $data): Threat + { + /** @var Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($uuid, $anr); - foreach ($instancesRisks as $i => $instanceRisk) { - $instanceRisk->threatRate = $data['qualification']; + $this->manageQualification($threat, $data); - // If qualification is forced, instances risks become inherited + $threat->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setConfidentiality((int)$data['c']) + ->setIntegrity((int)$data['i']) + ->setAvailability((int)$data['a']) + ->setUpdater($this->connectedUser->getEmail()); + if (isset($data['status'])) { + $threat->setStatus($data['status']); + } + if (isset($data['trend'])) { + $threat->setTrend((int)$data['trend']); + } + if (isset($data['comment'])) { + $threat->setComment($data['comment']); + } + if (!empty($data['theme']) && ( + $threat->getTheme() === null || $threat->getTheme()->getId() !== (int)$data['theme'] + )) { + /** @var Theme $theme */ + $theme = $this->themeTable->findById((int)$data['theme']); + $threat->setTheme($theme); + } + + $this->threatTable->save($threat); + + return $threat; + } + + public function patch(Anr $anr, string $uuid, array $data): Threat + { + /** @var Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($uuid, $anr); + + if (isset($data['status'])) { + $threat->setStatus((int)$data['status']) + ->setUpdater($this->connectedUser->getEmail()); + + $this->threatTable->save($threat); + } + + return $threat; + } + + public function delete(Anr $anr, string $uuid): void + { + /** @var Threat $threat */ + $threat = $this->threatTable->findByUuidAndAnr($uuid, $anr); + + $this->threatTable->remove($threat); + } + + public function deleteList(Anr $anr, array $data): void + { + $threats = $this->threatTable->findByUuidsAndAnr($data, $anr); + + $this->threatTable->removeList($threats); + } + + /** + * Can be set from 1st step, 2nd sub-step "Threats assessment". + * Updates the qualifications for the specified threat whenever they are created or updated. + * This noticeably handles qualification values inheritance. + */ + private function manageQualification(Threat $threat, array $data): void + { + if (isset($data['qualification'])) { + $threat->setQualification($data['qualification']); + + $instancesRisks = $this->instanceRiskTable->findByAnrAndThreatExcludeLocallySet( + $threat->getAnr(), + $threat, + empty($data['forceQualification']) + ); + foreach ($instancesRisks as $instanceRisk) { + $instanceRisk->setThreatRate((int)$data['qualification']); + + /* If qualification is forced, the instances risks threatRate's value is set from outside. */ if (!empty($data['forceQualification'])) { - $instanceRisk->mh = 1; + $instanceRisk->setIsThreatRateNotSetOrModifiedExternally(true); } - $instanceRiskTable->saveEntity($instanceRisk, false); + $this->anrInstanceRiskService->recalculateRiskRatesAndUpdateRecommendationsPositions($instanceRisk); - $instanceRiskService->updateRisks($instanceRisk); - $instanceRiskService->updateInstanceRiskRecommendationsPositions($instanceRisk); + $this->instanceRiskTable->save($instanceRisk, false); } + } + } - $instanceRiskTable->getDb()->flush(); + private function prepareThreatDataResult(Threat $threat): array + { + $themeData = null; + if ($threat->getTheme() !== null) { + $themeData = array_merge([ + 'id' => $threat->getTheme()->getId(), + ], $threat->getTheme()->getLabels()); + } + + return array_merge($threat->getLabels(), $threat->getDescriptions(), [ + 'uuid' => $threat->getUuid(), + 'anr' => [ + 'id' => $threat->getAnr()->getId(), + ], + 'code' => $threat->getCode(), + 'c' => $threat->getConfidentiality(), + 'i' => $threat->getIntegrity(), + 'a' => $threat->getAvailability(), + 'theme' => $themeData, + 'trend' => $threat->getTrend(), + 'qualification' => $threat->getQualification(), + 'mode' => $threat->getMode(), + 'comment' => $threat->getComment(), + 'status' => $threat->getStatus(), + ]); + } + + private function validateCia(Threat $threat): void + { + if ($threat->getConfidentiality() === 0 && $threat->getAvailability() === 0 && $threat->getIntegrity() === 0) { + throw new \Exception(); } } } diff --git a/src/Service/AnrThreatServiceFactory.php b/src/Service/AnrThreatServiceFactory.php deleted file mode 100755 index dc47b67f..00000000 --- a/src/Service/AnrThreatServiceFactory.php +++ /dev/null @@ -1,27 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Threat', - 'table' => 'Monarc\FrontOffice\Model\Table\ThreatTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'themeTable' => 'Monarc\FrontOffice\Model\Table\ThemeTable', - 'instanceRiskTable' => 'Monarc\FrontOffice\Model\Table\InstanceRiskTable', - 'instanceRiskService' => 'Monarc\FrontOffice\Service\AnrInstanceRiskService', - ]; -} diff --git a/src/Service/AnrVulnerabilityService.php b/src/Service/AnrVulnerabilityService.php index 58432151..0a978156 100755 --- a/src/Service/AnrVulnerabilityService.php +++ b/src/Service/AnrVulnerabilityService.php @@ -1,69 +1,144 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(FormattedInputParams $params): array { - // Do a soft limit, as we need to manually parse the codes to order them. - $data = $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - 1, - 0, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd - ); - - if ($order == "code" || $order == "-code") { - $desc = ($order == "-code"); - - // Codes might be in xx.xx.xx format which need a numerical sorting instead of an alphabetical one - $re = '/^[0-9]+$/m'; - usort($data, function ($a, $b) use ($re, $desc) { - $a['code'] = trim($a['code']); - $b['code'] = trim($b['code']); - $a_match = (preg_match($re, $a['code']) > 0); - $b_match = (preg_match($re, $b['code']) > 0); - - if ($a_match && $b_match) { - return $desc ? intval($b['code']) - intval($a['code']) : intval($a['code']) - intval($b['code']); - } else if ($a_match && !$b_match) { - return $desc ? 1 : -1; - } else if (!$a_match && $b_match) { - return $desc ? -1 : 1; - } else { - return $desc ? intval($b_match) - intval($a_match) : strcmp($a_match, $b_match); - } - }); + $result = []; + /** @var Vulnerability $vulnerability */ + foreach ($this->vulnerabilityTable->findByParams($params) as $vulnerability) { + $result[] = $this->prepareVulnerabilityDataResult($vulnerability); } - if(!empty($limit) && $limit > 0){ - return array_slice($data, ($page - 1) * $limit, $limit, false); - }else{ - return $data; + return $result; + } + + public function getCount(FormattedInputParams $params): int + { + return $this->vulnerabilityTable->countByParams($params); + } + + public function getVulnerabilityData(Anr $anr, string $uuid): array + { + /** @var Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($uuid, $anr); + + return $this->prepareVulnerabilityDataResult($vulnerability); + } + + public function create(Anr $anr, array $data, bool $saveInDb = true): Vulnerability + { + $vulnerability = (new Vulnerability()) + ->setAnr($anr) + ->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setCreator($this->connectedUser->getEmail()); + if (isset($data['uuid'])) { + $vulnerability->setUuid($data['uuid']); + } + if (isset($data['status'])) { + $vulnerability->setStatus((int)$data['status']); + } + if (isset($data['mode'])) { + $vulnerability->setMode((int)$data['mode']); + } + + $this->vulnerabilityTable->save($vulnerability, $saveInDb); + + return $vulnerability; + } + + public function createList(Anr $anr, array $data): array + { + $createdUuids = []; + foreach ($data as $row) { + $createdUuids[] = $this->create($anr, $row, false)->getUuid(); } + $this->vulnerabilityTable->flush(); + + return $createdUuids; + } + + public function update(Anr $anr, string $uuid, array $data): Vulnerability + { + /** @var Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($uuid, $anr); + + $vulnerability->setCode($data['code']) + ->setLabels($data) + ->setDescriptions($data) + ->setUpdater($this->connectedUser->getEmail()); + + $this->vulnerabilityTable->save($vulnerability); + + return $vulnerability; + } + + public function patch(Anr $anr, string $uuid, array $data): Vulnerability + { + /** @var Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($uuid, $anr); + + if (isset($data['status'])) { + $vulnerability->setStatus((int)$data['status'])->setUpdater($this->connectedUser->getEmail()); + + $this->vulnerabilityTable->save($vulnerability); + } + + return $vulnerability; + } + + public function delete(Anr $anr, string $uuid): void + { + /** @var Vulnerability $vulnerability */ + $vulnerability = $this->vulnerabilityTable->findByUuidAndAnr($uuid, $anr); + + $this->vulnerabilityTable->remove($vulnerability); + } + + public function deleteList(Anr $anr, array $data): void + { + /** @var Vulnerability[] $vulnerabilities */ + $vulnerabilities = $this->vulnerabilityTable->findByUuidsAndAnr($data, $anr); + + $this->vulnerabilityTable->removeList($vulnerabilities); + } + + protected function prepareVulnerabilityDataResult(VulnerabilitySuperClass $vulnerability): array + { + return array_merge($vulnerability->getLabels(), $vulnerability->getDescriptions(), [ + 'uuid' => $vulnerability->getUuid(), + 'anr' => [ + 'id' => $vulnerability->getAnr()->getId(), + ], + 'code' => $vulnerability->getCode(), + 'status' => $vulnerability->getStatus(), + 'mode' => $vulnerability->getMode(), + ]); } } diff --git a/src/Service/AnrVulnerabilityServiceFactory.php b/src/Service/AnrVulnerabilityServiceFactory.php deleted file mode 100755 index 0295dc01..00000000 --- a/src/Service/AnrVulnerabilityServiceFactory.php +++ /dev/null @@ -1,24 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Vulnerability', - 'table' => 'Monarc\FrontOffice\Model\Table\VulnerabilityTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - ]; -} diff --git a/src/Service/AssetExportService.php b/src/Service/AssetExportService.php deleted file mode 100644 index 6134c6ea..00000000 --- a/src/Service/AssetExportService.php +++ /dev/null @@ -1,11 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\AssetTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\Asset', - 'amvService' => 'Monarc\FrontOffice\Service\AmvService', - ]; -} diff --git a/src/Service/ClientService.php b/src/Service/ClientService.php index 15d47a14..250abfe8 100755 --- a/src/Service/ClientService.php +++ b/src/Service/ClientService.php @@ -1,22 +1,24 @@ clientTable = $clientTable; + $this->connectedUser = $connectedUserService->getConnectedUser(); } public function getAll(): array @@ -36,13 +38,25 @@ public function getAll(): array ]; } + public function create(array $data): void + { + $client = (new Client()) + ->setName($data['name']) + ->setContactEmail($data['contact_email']) + ->setCreator($this->connectedUser->getEmail()); + + $this->clientTable->save($client); + } + public function patch(int $id, array $data): void { + /** @var Client $client */ $client = $this->clientTable->findById($id); - $client->setName($data['name']); - $client->setContactEmail($data['contact_email']); + $client->setName($data['name']) + ->setContactEmail($data['contact_email']) + ->setUpdater($this->connectedUser->getEmail()); - $this->clientTable->saveEntity($client); + $this->clientTable->save($client); } } diff --git a/src/Service/DeliverableGenerationService.php b/src/Service/DeliverableGenerationService.php index 22a9554f..2c1bd36e 100644 --- a/src/Service/DeliverableGenerationService.php +++ b/src/Service/DeliverableGenerationService.php @@ -1,317 +1,220 @@ -language = $lang; - } - - /** - * Translates the provided input text into the current ANR language - * @param string $text The text to translate - * @return string THe translated text, or $text if no translation was found - */ - public function anrTranslate($text) - { - return $this->get('translateService')->translate($text, $this->currentLangAnrIndex); - } - - /** - * Returns the list of delivery models. - * @return array An array of delivery models - * @see DeliveriesModelsService::getList() - */ - public function getDeliveryModels() - { - return $this->deliveryModelService->getList(1, 0, null, null, null); + private UserSuperClass $connectedUser; + + private int $currentLangAnrIndex = 1; + + private ?Entity\Anr $anr; + + private $noBorderTable; + + private $borderTable; + private $whiteBigBorderTable; + private $tblHeader; + private $normalFont; + + private $boldFont; + private $whiteFont; + private $redFont; + private $titleFont; + private $centerParagraph; + + private $leftParagraph; + private $verticalCenterParagraph; + private $grayCell; + + private $blackCell; + private $customizableCell; + private $vAlignCenterCell; + private $continueCell; + private $colSpanCell; + private $rotate90TextCell; + private $restartAndGrayCell; + private $continueAndGrayCell; + private $restartAndBlackCell; + private $continueAndBlackCell; + private $restartAndCenterCell; + private $restartAndTopCell; + private $barChart; + + public function __construct( + private Table\DeliveryTable $deliveryTable, + private AnrInstanceConsequenceService $anrInstanceConsequenceService, + private Table\InstanceTable $instanceTable, + private Table\InstanceRiskTable $instanceRiskTable, + private Table\InstanceRiskOpTable $instanceRiskOpTable, + private Table\SoaScaleCommentTable $soaScaleCommentTable, + private Table\RecommendationRiskTable $recommendationRiskTable, + private Table\RecommendationHistoryTable $recommendationHistoryTable, + private Table\AnrInstanceMetadataFieldTable $anrInstanceMetadataFieldTable, + private Table\InstanceRiskOwnerTable $instanceRiskOwnerTable, + private Table\ThreatTable $threatTable, + private Table\ClientTable $clientTable, + private Table\MeasureTable $measureTable, + private RecordTable $recordTable, + private DeliveriesModelsTable $deliveriesModelsTable, + private OperationalRiskScaleService $operationalRiskScaleService, + private AnrQuestionService $anrQuestionService, + private AnrQuestionChoiceService $anrQuestionChoiceService, + private AnrInterviewService $interviewService, + private AnrCartoRiskService $cartoRiskService, + private AnrInstanceRiskOpService $anrInstanceRiskOpService, + private AnrInstanceRiskService $anrInstanceRiskService, + private CoreService\Helper\ScalesCacheHelper $scalesCacheHelper, + private CoreService\TranslateService $translateService, + CoreService\ConnectedUserService $connectedUserService + ) { + $this->connectedUser = $connectedUserService->getConnectedUser(); } /** - * Retrieve the previous delivery for the specified type of document, or all types if none is specified. - * @param int $anrId The ANR ID - * @param null|int $typeDoc The type of document, or null to retrieve all - * @return array The previous deliveries + * Retrieve the previous delivery for the specified type of document. */ - public function getLastDeliveries($anrId, $typeDoc = null) + public function getLastDelivery(Entity\Anr $anr, int $docType): array { - /** @var DeliveryTable $table */ - $table = $this->get('table'); - - // If typedoc is specified, retrieve only the last delivery of typedoc. Else, retrieve last delivery for each - // type of document. - if (!empty($typeDoc)) { - $deliveries = $table->getEntityByFields(['anr' => $anrId, 'typedoc' => $typeDoc], ['createdAt' => 'DESC']); - $lastDelivery = null; - foreach ($deliveries as $delivery) { - $lastDelivery = $delivery->getJsonArray(); - break; - } - - return $lastDelivery; - } else { - $deliveries = $table->getEntityByFields(['anr' => $anrId], ['createdAt' => 'DESC']); - $lastDelivery = []; - foreach ($deliveries as $delivery) { - if (empty($lastDelivery[$delivery->get('typedoc')])) { - $lastDelivery[$delivery->get('typedoc')] = $delivery->getJsonArray(); - } - if (count($lastDelivery) == 3) { - break; - } - } - - return array_values($lastDelivery); - } + $lastDelivery = $this->deliveryTable->findLastByAnrAndDocType($anr, $docType); + if ($lastDelivery === null) { + return []; + } + + return [ + 'id' => $lastDelivery->getId(), + 'typedoc' => $lastDelivery->getDocType(), + 'name' => $lastDelivery->getName(), + 'version' => $lastDelivery->getVersion(), + 'status' => $lastDelivery->getStatus(), + 'classification' => $lastDelivery->getClassification(), + 'respCustomer' => $lastDelivery->getRespCustomer(), + 'respSmile' => $lastDelivery->getResponsibleManager(), + 'summaryEvalRisk' => $lastDelivery->getSummaryEvalRisk(), + ]; } /** - * Generates the deliverable Word file - * @param int $anrId The ANR ID - * @param int $typeDoc The type of document model - * @param array $values The values to fill in the document - * @param array $data The user-provided data when generating the deliverable - * @return string The output file path - * @throws \Monarc\Core\Exception\Exception If the model or ANR are not found. + * Generates the deliverable Word file. + * + * @return string The output file path. */ - public function generateDeliverableWithValues($anrId, $typeDoc, $values, $data) + public function generateDeliverableWithValues(Entity\Anr $anr, int $docType, array $data): string { - $this->anr = $this->anrTable->findById($anrId); - $this->currentLangAnrIndex = $this->anr->getLanguage(); - - $model = current($this->deliveryModelService->get("table")->getEntityByFields(['id' => $data['template']])); - if (!$model) { - throw new \Monarc\Core\Exception\Exception("Model `id` not found"); - } + $delivery = (new Entity\Delivery()) + ->setAnr($anr) + ->setDocType($docType) + ->setName($data['docname'] ?? '') + ->setRespCustomer($data['consultants'] ?? '') + ->setResponsibleManager($data['managers'] ?? '') + ->setClassification($data['classification'] ?? '') + ->setVersion($data['version']) + ->setStatus((int)($data['status'] ?? 0)) + ->setSummaryEvalRisk($data['summaryEvalRisk'] ?? '') + ->setCreator($this->connectedUser->getEmail()); + $this->deliveryTable->save($delivery); + + $this->anr = $anr; + $this->currentLangAnrIndex = $anr->getLanguage(); + + $deliveryModel = $this->deliveriesModelsTable->findById((int)$data['template']); - $delivery = $this->get('entity'); - - $data['respCustomer'] = $data['consultants']; - $data['respSmile'] = $data['managers']; - $data['name'] = $data['docname']; - - $values['txt']['SUMMARY_EVAL_RISK'] = $this->generateWordXmlFromHtml(_WT($values['txt']['SUMMARY_EVAL_RISK'])); - - unset($data['id']); - $delivery->exchangeArray($data); - - $dependencies = (property_exists($this, 'dependencies')) ? $this->dependencies : []; - $this->setDependencies($delivery, $dependencies); - - /** @var DeliveryTable $table */ - $table = $this->get('table'); - $table->save($delivery); - - //find the right model - $pathModel = getenv('APP_CONF_DIR') ? getenv('APP_CONF_DIR') : ''; - $pathLang = ''; - - switch ($this->currentLangAnrIndex) { - case 1: - $pathLang = $model->path1; - break; - case 2: - $pathLang = $model->path2; - break; - case 3: - $pathLang = $model->path3; - break; - case 4: - $pathLang = $model->path4; - break; - default: - break; - } - $pathModel .= $pathLang; - if (!file_exists($pathModel)) { - // if template not available in the language of the ANR, use the - // default template of the category - $pathModel = getenv('APP_CONF_DIR') ? getenv('APP_CONF_DIR') : ''; - $model = current($this->deliveryModelService->get("table")->getEntityByFields(['category' => $typeDoc, - 'path2' => ['op' => 'IS NOT', 'value' => null]])); - $pathModel .= $model->path2; - // throw new \Monarc\Core\Exception\Exception("Model not found for the language"); - } + $values = [ + 'txt' => [ + 'VERSION' => htmlspecialchars($delivery->getVersion()), + 'STATE' => $delivery->getStatus() === 0 ? 'Draft' : 'Final', + 'CLASSIFICATION' => htmlspecialchars($delivery->getClassification()), + 'COMPANY' => htmlspecialchars($this->clientTable->findFirstClient()->getName()), + 'DOCUMENT' => htmlspecialchars($delivery->getName()), + 'DATE' => date('d/m/Y'), + 'CLIENT' => htmlspecialchars($delivery->getResponsibleManager()), + 'SMILE' => htmlspecialchars($delivery->getRespCustomer()), + 'SUMMARY_EVAL_RISK' => $this->generateWordXmlFromHtml(_WT($delivery->getSummaryEvalRisk())), + ], + ]; + $pathModel = (getenv('APP_CONF_DIR') ?: '') . $deliveryModel->getPath($this->currentLangAnrIndex); if (!file_exists($pathModel)) { - throw new \Monarc\Core\Exception\Exception("Model not found " . $pathModel); + /* if template not available in the language of the ANR, use the default template of the category. */ + $pathModel = getenv('APP_CONF_DIR') ?? ''; + $deliveryModel = current( + $this->deliveriesModelsTable->getEntityByFields([ + 'category' => $docType, + 'path2' => ['op' => 'IS NOT', 'value' => null], + ]) + ); + $pathModel .= $deliveryModel->path2; + if (!file_exists($pathModel)) { + throw new Exception('Model not found "' . $pathModel . '"'); + } } - $referential = $data['referential'] ?? null; - + $referentialUuid = $data['referential'] ?? null; $risksByControl = $data['risksByControl'] ?? false; - $record = $data['record'] ?? null; - $values = array_merge_recursive($values, $this->buildValues($typeDoc, $referential, $record, $risksByControl)); + $values = array_merge_recursive( + $values, + $this->buildValues($docType, $referentialUuid, $record, $risksByControl) + ); return $this->generateDeliverableWithValuesAndModel($pathModel, $values); } + /** + * Translates the provided input text into the current ANR language + * + * @param string $text The text to translate + * + * @return string THe translated text, or $text if no translation was found + */ + private function anrTranslate(string $text): string + { + return $this->translateService->translate($text, $this->currentLangAnrIndex); + } + /** * Method called by generateDeliverableWithValues to generate the model from its path and values. - * @see #generateDeliverableWithValues + * * @param string $modelPath The file path to the DOCX model to use * @param array $values The values to fill in the document - * @return string The path to the generated document - * @throws \Monarc\Core\Exception\Exception If the model is not found + * + * @return string The path to the generated temporary document. */ - protected function generateDeliverableWithValuesAndModel($modelPath, $values) + private function generateDeliverableWithValuesAndModel(string $modelPath, array $values): string { - //verify template exist + /* Verify the template existence. */ if (!file_exists($modelPath)) { - throw new \Monarc\Core\Exception\Exception("Model path not found: " . $modelPath); + throw new Exception("Model path not found: " . $modelPath); } - //create word - $word = new TemplateProcessor($modelPath); + $word = new PhpWord\TemplateProcessor($modelPath); if (!empty($values['txt'])) { foreach ($values['txt'] as $key => $value) { @@ -336,82 +239,43 @@ protected function generateDeliverableWithValuesAndModel($modelPath, $values) } } - $datapath = './data/'; - $appconfdir = getenv('APP_CONF_DIR') ? getenv('APP_CONF_DIR') : ''; - if (!empty($appconfdir)) { - $datapath = $appconfdir . '/data/'; - } - $pathTmp = $datapath . uniqid("", true) . "_" . microtime(true) . ".docx"; - $word->saveAs($pathTmp); - - // Test export to PDF with DomPDF - // $pathTmp1 = $datapath . uniqid("", true) . "_" . microtime(true) . ".pdf"; - // \PhpOffice\PhpWord\Settings::setPdfRendererPath('vendor/dompdf/dompdf'); - // \PhpOffice\PhpWord\Settings::setPdfRendererName('DomPDF'); - // $phpWord = \PhpOffice\PhpWord\IOFactory::load($pathTmp); - // //Save it - // $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'PDF'); - // $xmlWriter->save($pathTmp1); - - return $pathTmp; - } - - /** - * Returns a human-readable string for the provided model type - * @param int $modelCategory The model type value - * @return string The model type description - */ - protected function getModelType($modelCategory) - { - switch ($modelCategory) { - case 1: - return 'Validation du contexte'; - case 2: - return 'Validation du modèle'; - case 3: - return 'Rapport final'; - case 4: - return 'Plan implementation des recommendations'; - case 5: - return 'Statement of applicability'; - default: - return 'N/A'; - } + return $word->save(); } /** - * Builds the values to fill in the word document + * Builds the values to fill in the word document. + * * @param int $modelCategory The model type + * * @return array The values for the Word document as a key-value array */ - protected function buildValues($modelCategory, $referential = null, $record = null, $risksByControl = false) - { + private function buildValues( + $modelCategory, + ?string $referentialUuid = null, + $record = null, + $risksByControl = false + ): array { $this->setStyles(); - switch ($modelCategory) { - case 1: - return $this->buildContextValidationValues(); - case 2: - return $this->buildContextModelingValues(); - case 3: - return $this->buildRiskAssessmentValues(); - case 4: - return $this->buildImplementationPlanValues(); - case 5: - return $this->buildStatementOfAppplicabilityValues($referential, $risksByControl); - case 6: - return $this->buildRecordOfProcessingActivitiesValues($record); - case 7: - return $this->buildAllRecordsValues(); - default: - return []; - } + return match ($modelCategory) { + DeliveriesModels::MODEL_CONTEXT_VALIDATION => $this->buildContextValidationValues(), + DeliveriesModels::MODEL_ASSETS_AND_MODELS_VALIDATION => $this->buildContextModelingValues(), + DeliveriesModels::MODEL_RISK_ANALYSIS => $this->buildRiskAssessmentValues(), + DeliveriesModels::MODEL_IMPLEMENTATION_PLAN => $this->buildImplementationPlanValues(), + DeliveriesModels::MODEL_STATEMENT_OF_APPLICABILITY => $referentialUuid + ? $this->buildStatementOfAppplicabilityValues($referentialUuid, $risksByControl) + : [], + DeliveriesModels::MODEL_RECORD_OF_PROCESSING_ACTIVITIES => $this + ->buildRecordOfProcessingActivitiesValues($record), + DeliveriesModels::MODEL_ALL_RECORD_OF_PROCESSING_ACTIVITIES => $this->buildAllRecordsValues(), + default => [], + }; } /** * Set table styles */ - protected function setStyles() + private function setStyles() { //Table Style $this->noBorderTable = ['align' => 'center', 'cellMarginRight' => '0']; @@ -440,7 +304,7 @@ protected function setStyles() $this->colSpanCell = $this->vAlignCenterCell; $this->rotate90TextCell = array_merge( $this->vAlignCenterCell, - ['vMerge' => 'restart','textDirection' => 'btLr'] + ['vMerge' => 'restart', 'textDirection' => 'btLr'] ); $this->restartAndGrayCell = array_merge($this->grayCell, ['vMerge' => 'restart']); $this->continueAndGrayCell = array_merge($this->continueCell, $this->grayCell); @@ -451,10 +315,10 @@ protected function setStyles() //Chart styles $this->barChart = [ - 'width' => Converter::cmToEmu(17), - 'height' => Converter::cmToEmu(9.5), + 'width' => PhpWord\Shared\Converter::cmToEmu(17), + 'height' => PhpWord\Shared\Converter::cmToEmu(9.5), 'dataLabelOptions' => ['showCatName' => false], - 'colors' => ['D6F107','FFBC1C','FD661F'], + 'colors' => ['D6F107', 'FFBC1C', 'FD661F'], 'showAxisLabels' => true, 'showGridY' => true, ]; @@ -462,135 +326,100 @@ protected function setStyles() /** * Set Span and Color Cell + * * @param int $nCol number of columns * @param string $color HEX color + * * @return array $this->colSpanCell */ - protected function setColSpanCell($nCol, $color = null) + private function setColSpanCell($nCol, $color = null): array { $this->colSpanCell['gridSpan'] = $nCol; $this->colSpanCell['bgcolor'] = $color; + return $this->colSpanCell; } /** - * Set bgColor by thresholds value - * @param int $nCol number of columns + * Set bgColor by thresholds value. + * + * @param int|string $nCol number of columns * @param string $color HEX color + * * @return array $this->colSpanCell */ - protected function setBgColorCell($value, $infoRisk = true) + private function setBgColorCell($value, bool $infoRisk = true): array { if ($infoRisk) { $thresholds = [ - 'low' => $this->anr->seuil1, - 'high' => $this->anr->seuil2, + 'low' => $this->anr->getSeuil1(), + 'high' => $this->anr->getSeuil2(), ]; } else { $thresholds = [ - 'low' => $this->anr->seuilRolf1, - 'high' => $this->anr->seuilRolf2, + 'low' => $this->anr->getSeuilRolf1(), + 'high' => $this->anr->getSeuilRolf2(), ]; } if ($value === null) { $this->customizableCell['BgColor'] = 'E7E6E6'; + return $this->customizableCell; } + $this->customizableCell['BgColor'] = 'FD661F'; if ($value === '-') { $this->customizableCell['BgColor'] = ''; } elseif ($value <= $thresholds['low']) { $this->customizableCell['BgColor'] = 'D6F107'; } elseif ($value <= $thresholds['high']) { $this->customizableCell['BgColor'] = 'FFBC1C'; - } else { - $this->customizableCell['BgColor'] = 'FD661F'; } return $this->customizableCell; } /** - * Build values for Step 1 deliverable (context validation) - * @return array The key-value array + * Build values for Step 1 deliverable (context validation). */ - protected function buildContextValidationValues() + private function buildContextValidationValues(): array { - $impactsScale = current(current( - $this->scaleService->getList(1, 0, null, null, ['anr' => $this->anr->getId(), 'type' => 1]) - )); - $impactsTypes = $this->scaleTypeService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); - $impactsComments = $this->scaleCommentService->getList( - 1, - 0, - null, - null, - ['anr' => $this->anr->getId(), 'scale' => $impactsScale['id']] - ); - $threatsScale = current(current($this->scaleService->getList( - 1, - 0, - null, - null, - ['anr' => $this->anr->getId(), 'type' => 2] - ))); - $threatsComments = $this->scaleCommentService->getList( - 1, - 0, - null, - null, - ['anr' => $this->anr->getId(), 'scale' => $threatsScale['id']] - ); - $vulnsScale = current(current($this->scaleService->getList( - 1, - 0, - null, - null, - ['anr' => $this->anr->getId(), 'type' => 3] - ))); - $vulnsComments = $this->scaleCommentService->getList( - 1, - 0, - null, - null, - ['anr' => $this->anr->getId(), 'scale' => $vulnsScale['id']] - ); - - $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr->getId()); - $opRisksImpactsScaleType = array_values(array_filter($opRisksAllScales, function ($scale) { - return $scale['type'] == 1; + /** + * @var Entity\Scale $impactsScale + * @var Entity\Scale $threatsScale + * @var Entity\Scale $vulnsScale + */ + $impactsScale = $this->scalesCacheHelper->getCachedScaleByType($this->anr, ScaleSuperClass::TYPE_IMPACT); + $threatsScale = $this->scalesCacheHelper->getCachedScaleByType($this->anr, ScaleSuperClass::TYPE_THREAT); + $vulnsScale = $this->scalesCacheHelper->getCachedScaleByType($this->anr, ScaleSuperClass::TYPE_VULNERABILITY); + + $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr); + $opRisksImpactsScaleType = array_values(array_filter($opRisksAllScales, static function ($scale) { + return $scale['type'] === OperationalRiskScaleSuperClass::TYPE_IMPACT; })); $opRisksImpactsScaleMin = $opRisksImpactsScaleType[0]['min']; $opRisksImpactsScaleMax = $opRisksImpactsScaleType[0]['max']; - $opRisksImpactsScales = array_values(array_filter($opRisksImpactsScaleType[0]['scaleTypes'], function ($scale) { - return $scale['isHidden'] == false; - })); - $opRisksLikelihoodScale = array_values(array_filter($opRisksAllScales, function ($scale) { - return $scale['type'] == 2; + $opRisksImpactsScales = array_values( + array_filter($opRisksImpactsScaleType[0]['scaleTypes'], static function ($scale) { + return !$scale['isHidden']; + }) + ); + $opRisksLikelihoodScale = array_values(array_filter($opRisksAllScales, static function ($scale) { + return $scale['type'] === OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD; }))[0]; - $values = [ + return [ 'xml' => [ - 'CONTEXT_ANA_RISK' => $this->generateWordXmlFromHtml(_WT($this->anr->contextAnaRisk)), - 'CONTEXT_GEST_RISK' => $this->generateWordXmlFromHtml(_WT($this->anr->contextGestRisk)), - 'SYNTH_EVAL_THREAT' => $this->generateWordXmlFromHtml(_WT($this->anr->synthThreat)), + 'CONTEXT_ANA_RISK' => $this->generateWordXmlFromHtml(_WT($this->anr->getContextAnaRisk())), + 'CONTEXT_GEST_RISK' => $this->generateWordXmlFromHtml(_WT($this->anr->getContextGestRisk())), + 'SYNTH_EVAL_THREAT' => $this->generateWordXmlFromHtml(_WT($this->anr->getSynthThreat())), ], 'table' => [ - 'SCALE_IMPACT' => $this->generateInformationalRiskImpactsTable( - $impactsScale, - $impactsTypes, - $impactsComments - ), - 'SCALE_THREAT' => $this->generateThreatOrVulnerabilityScaleTable( - $threatsScale, - $threatsComments - ), - 'SCALE_VULN' => $this->generateThreatOrVulnerabilityScaleTable( - $vulnsScale, - $vulnsComments - ), + 'SCALE_IMPACT' => $this->generateInformationalRiskImpactsTable($impactsScale), + 'SCALE_THREAT' => $this->generateThreatOrVulnerabilityScaleTable($threatsScale), + 'SCALE_VULN' => $this->generateThreatOrVulnerabilityScaleTable($vulnsScale), 'TABLE_RISKS' => $this->generateInformationalRiskAcceptanceThresholdsTable( $impactsScale, $threatsScale, @@ -610,26 +439,24 @@ protected function buildContextValidationValues() $opRisksImpactsScaleMin, $opRisksImpactsScaleMax ), - 'TABLE_THREATS' => $this->generateThreatsTable(false), + 'TABLE_THREATS' => $this->generateThreatsTable(), 'TABLE_EVAL_TEND' => $this->generateTrendAssessmentTable(), 'TABLE_THREATS_FULL' => $this->generateThreatsTable(true), 'TABLE_INTERVIEW' => $this->generateInterviewsTable(), ], ]; - - return $values; } /** * Build values for Step 2 deliverable (context modeling) * @return array The key-value array */ - protected function buildContextModelingValues() + private function buildContextModelingValues() { // Models are incremental, so use values from level-1 model $values = $this->buildContextValidationValues(); - $values['xml']['SYNTH_ACTIF'] = $this->generateWordXmlFromHtml(_WT($this->anr->synthAct)); + $values['xml']['SYNTH_ACTIF'] = $this->generateWordXmlFromHtml(_WT($this->anr->getSynthAct())); $values['table']['IMPACTS_APPRECIATION'] = $this->generateImpactsAppreciation(); return $values; @@ -639,90 +466,75 @@ protected function buildContextModelingValues() * Build values for Step 3 deliverable (risk assessment) * @return array The key-value array */ - protected function buildRiskAssessmentValues() + private function buildRiskAssessmentValues() { // Models are incremental, so use values from level-2 model $values = $this->buildContextModelingValues(); - $values = array_merge_recursive( - $values, - ['chart' => [ + $values = array_merge_recursive($values, [ + 'chart' => [ 'GRAPH_EVAL_RISK' => $this->generateRisksGraph(), 'GRAPH_EVAL_OP_RISK' => $this->generateRisksGraph(false), - ]] - ); + ] + ]); - $values = array_merge_recursive( - $values, - ['table' => [ + $values = array_merge_recursive($values, [ + 'table' => [ 'RISKS_RECO_FULL' => $this->generateRisksPlan(), 'OPRISKS_RECO_FULL' => $this->generateOperationalRisksPlan(), 'TABLE_RISK_OWNERS' => $this->generateOwnersTable(), - ]] - ); + ] + ]); - $values = array_merge_recursive( + return array_merge_recursive( $values, - ['xml' => [ - 'DISTRIB_EVAL_RISK' => $this->generateWordXmlFromHtml(_WT($this->getRisksDistribution())), - 'DISTRIB_EVAL_OP_RISK' => $this->generateWordXmlFromHtml(_WT($this->getRisksDistribution(false))), - 'CURRENT_RISK_MAP' => $this->generateCurrentRiskMap('real'), - 'TARGET_RISK_MAP' => $this->generateCurrentRiskMap('targeted'), - 'TABLE_ASSET_CONTEXT' => $this->generateAssetContextTable(), - 'RISKS_KIND_OF_TREATMENT' => $this->generateRisksByKindOfTreatment(), - 'TABLE_AUDIT_INSTANCES' => $this->generateTableAudit(), - 'TABLE_AUDIT_RISKS_OP' => $this->generateTableAuditOp(), - ]] + [ + 'xml' => [ + 'DISTRIB_EVAL_RISK' => $this->generateWordXmlFromHtml(_WT($this->getRisksDistribution())), + 'DISTRIB_EVAL_OP_RISK' => $this->generateWordXmlFromHtml(_WT($this->getRisksDistribution(false))), + 'CURRENT_RISK_MAP' => $this->generateCurrentRiskMap(), + 'TARGET_RISK_MAP' => $this->generateCurrentRiskMap('targeted'), + 'TABLE_ASSET_CONTEXT' => $this->generateAssetContextTable(), + 'RISKS_KIND_OF_TREATMENT' => $this->generateRisksByKindOfMeasure(), + 'TABLE_AUDIT_INSTANCES' => $this->generateTableAudit(), + 'TABLE_AUDIT_RISKS_OP' => $this->generateTableAuditOp(), + ], + ] ); - - return $values; } /** * Build values for Step 4 deliverable (Implementation plan) * @return array The key-value array */ - protected function buildImplementationPlanValues() + private function buildImplementationPlanValues() { - $values = [ + return [ 'table' => [ 'TABLE_IMPLEMENTATION_PLAN' => $this->generateTableImplementationPlan(), 'TABLE_IMPLEMENTATION_HISTORY' => $this->generateTableImplementationHistory(), ], ]; - - return $values; } /** * Build values for Step 5 deliverable (Statement Of Applicability) * @return array The key-value array */ - protected function buildStatementOfAppplicabilityValues($referential, $risksByControl) + private function buildStatementOfAppplicabilityValues(string $referentialUuid, $risksByControl) { - $values = []; - $soaScaleComments = array_filter( - $this->soaScaleCommentTable->findByAnr($this->anr), - function ($soaScaleComment) { - return !$soaScaleComment->isHidden(); - } - ); - $translations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $this->anr, - [Translation::SOA_SCALE_COMMENT], - $this->configService->getActiveLanguageCodes()[$this->anr->getLanguage()] - ); - - $values['table']['TABLE_STATEMENT_OF_APPLICABILITY_SCALE'] = $this->generateTableStatementOfApplicabilityScale( - $soaScaleComments, - $translations - ); - $values['table']['TABLE_STATEMENT_OF_APPLICABILITY'] = $this->generateTableStatementOfApplicability( - $referential, - $translations - ); + /** @var Entity\SoaScaleComment[] $soaScaleComments */ + $soaScaleComments = $this->soaScaleCommentTable->findByAnrOrderByIndex($this->anr, true); + $values = [ + 'table' => [ + 'TABLE_STATEMENT_OF_APPLICABILITY_SCALE' => $this->generateTableStatementOfApplicabilityScale( + $soaScaleComments + ), + 'TABLE_STATEMENT_OF_APPLICABILITY' => $this->generateTableStatementOfApplicability($referentialUuid), + ], + ]; if ($risksByControl) { - $values['xml']['TABLE_RISKS_BY_CONTROL'] = $this->generateTableRisksByControl($referential); + $values['xml']['TABLE_RISKS_BY_CONTROL'] = $this->generateTableRisksByControl($referentialUuid); } else { $values['txt']['TABLE_RISKS_BY_CONTROL'] = null; } @@ -734,9 +546,9 @@ function ($soaScaleComment) { * Build values for Step 5 deliverable (Record of Processing Activities) * @return array The key-value array */ - protected function buildRecordOfProcessingActivitiesValues($record) + private function buildRecordOfProcessingActivitiesValues($record) { - $values = [ + return [ 'xml' => [ 'TABLE_RECORD_INFORMATION' => $this->generateTableRecordGDPR($record), 'TABLE_RECORD_ACTORS' => $this->generateTableRecordActors($record), @@ -746,15 +558,13 @@ protected function buildRecordOfProcessingActivitiesValues($record) 'TABLE_RECORD_PROCESSORS' => $this->generateTableRecordProcessors($record), ], ]; - - return $values; } /** * Build values for Step 5 deliverable (All Records of Processing Activities) * @return array The key-value array */ - protected function buildAllRecordsValues() + private function buildAllRecordsValues() { $values['xml']['TABLE_ALL_RECORDS'] = $this->generateTableAllRecordsGDPR(); @@ -762,151 +572,103 @@ protected function buildAllRecordsValues() } /** - * Generate Informational Risk Impacts table - * @return Table + * Generate Informational Risk Impacts table. */ - protected function generateInformationalRiskImpactsTable($impactsScale, $impactsTypes, $impactsComments) + private function generateInformationalRiskImpactsTable(Entity\Scale $impactScale): PhpWord\Element\Table { - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Level'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(8.40), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(8.60), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Consequences'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Level'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.40), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.60), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Consequences'), $this->boldFont, $this->centerParagraph); // Manually add C/I/D impacts columns $table->addRow(); - $table->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); - $table->addCell(Converter::cmToTwip(2.80), $this->grayCell) - ->addText( - $this->anrTranslate('Confidentiality'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.80), $this->grayCell) - ->addText( - $this->anrTranslate('Integrity'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.80), $this->grayCell) - ->addText( - $this->anrTranslate('Availability'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(8.60), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.80), $this->grayCell) + ->addText($this->anrTranslate('Confidentiality'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.80), $this->grayCell) + ->addText($this->anrTranslate('Integrity'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.80), $this->grayCell) + ->addText($this->anrTranslate('Availability'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.60), $this->continueAndGrayCell); - // Fill in each row - for ($row = $impactsScale['min']; $row <= $impactsScale['max']; ++$row) { - $table->addRow(400); - $table->addCell(Converter::cmToTwip(2.00), $this->restartAndTopCell) - ->addText( - $row, - $this->normalFont, - $this->centerParagraph - ); - - $impactsTypePerType = []; - - foreach ($impactsTypes as $impactType) { - $impactsTypePerType[$impactType['type_id']] = $impactType; + // Put C/I/D first + $scaleImpactTypesPerType = []; + foreach ($impactScale->getScaleImpactTypes() as $scaleImpactType) { + if (!$scaleImpactType->isHidden()) { + $scaleImpactTypesPerType[$scaleImpactType->getType()] = $scaleImpactType; } + } + ksort($scaleImpactTypesPerType); - // Put C/I/D first - for ($i = 1; $i <= 3; ++$i) { - $impactType = $impactsTypePerType[$i]; + // Fill in each row + for ($scaleIndex = $impactScale->getMin(); $scaleIndex <= $impactScale->getMax(); ++$scaleIndex) { + $table->addRow(400); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndTopCell) + ->addText((string)$scaleIndex, $this->normalFont, $this->centerParagraph); - // Find the appropriate comment + $first = true; + foreach ($scaleImpactTypesPerType as $type => $scaleImpactType) { $commentText = ''; - foreach ($impactsComments as $comment) { - if ($comment['scaleImpactType']->id == $impactType['id'] && $comment['scaleIndex'] == $row) { - $commentText = $comment['comment' . $this->currentLangAnrIndex]; + foreach ($scaleImpactType->getScaleComments() as $scaleComment) { + if ($scaleComment->getScaleIndex() === $scaleIndex) { + $commentText = $scaleComment->getComment($this->currentLangAnrIndex); break; } } - - $table->addCell(Converter::cmToTwip(2.80), $this->restartAndTopCell) - ->addText( - _WT($commentText), - $this->normalFont, - $this->leftParagraph + if (in_array($type, ScaleImpactTypeSuperClass::getScaleImpactTypesCid(), true)) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.80), $this->restartAndTopCell) + ->addText(_WT($commentText), $this->normalFont, $this->leftParagraph); + } else { + // Then ROLFP and custom columns as rows + if (!$first) { + $table->addRow(400); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.15), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.15), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.15), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.15), $this->continueCell); + } + $cellConsequences = $table + ->addCell(PhpWord\Shared\Converter::cmToTwip(2.80), $this->vAlignCenterCell); + $cellConsequencesRun = $cellConsequences->addTextRun($this->leftParagraph); + $cellConsequencesRun->addText( + _WT($this->anrTranslate($scaleImpactType->getLabel($this->currentLangAnrIndex))) . ' : ', + $this->boldFont ); - } - - // Then ROLFP and custom columns as rows - $first = true; - foreach ($impactsTypes as $impactType) { - if ($impactType['type_id'] < 4 || $impactType['isHidden']) { - continue; - } + $cellConsequencesRun->addText(_WT($commentText), $this->normalFont); - if ($first) { $first = false; - } else { - $table->addRow(400); - $table->addCell(Converter::cmToTwip(2.15), $this->continueCell); - $table->addCell(Converter::cmToTwip(2.15), $this->continueCell); - $table->addCell(Converter::cmToTwip(2.15), $this->continueCell); - $table->addCell(Converter::cmToTwip(2.15), $this->continueCell); - } - - // Find the appropriate comment - $commentText = ''; - foreach ($impactsComments as $comment) { - if ($comment['scaleImpactType']->id == $impactType['id'] && $comment['scaleIndex'] == $row) { - $commentText = $comment['comment' . $this->currentLangAnrIndex]; - break; - } } - - $cellConsequences = $table->addCell(Converter::cmToTwip(2.80), $this->vAlignCenterCell); - $cellConsequencesRun = $cellConsequences->addTextRun($this->leftParagraph); - $cellConsequencesRun->addText( - _WT($this->anrTranslate($impactType['label' . $this->currentLangAnrIndex])) . ' : ', - $this->boldFont - ); - $cellConsequencesRun->addText( - _WT($commentText), - $this->normalFont - ); } } + return $table; } /** - * Generate Informational Risk Acceptance thresholds table - * @return Table + * Generate Informational Risk Acceptance thresholds table. */ - protected function generateInformationalRiskAcceptanceThresholdsTable($impactsScale, $threatsScale, $vulnsScale) - { - $tableWord = new PhpWord(); + private function generateInformationalRiskAcceptanceThresholdsTable( + Entity\Scale $impactsScale, + Entity\Scale $threatsScale, + Entity\Scale $vulnsScale + ): PhpWord\Element\Table { + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->noBorderTable); $header = []; - for ($t = $threatsScale['min']; $t <= $threatsScale['max']; ++$t) { - for ($v = $vulnsScale['min']; $v <= $vulnsScale['max']; ++$v) { + for ($t = $threatsScale->getMin(); $t <= $threatsScale->getMax(); ++$t) { + for ($v = $vulnsScale->getMin(); $v <= $vulnsScale->getMax(); ++$v) { $prod = $t * $v; - if (array_search($prod, $header) === false) { + if (!in_array($prod, $header, true)) { $header[] = $prod; } } @@ -917,48 +679,27 @@ protected function generateInformationalRiskAcceptanceThresholdsTable($impactsSc $table->addRow(); $table->addCell(null, $this->setColSpanCell(2)); $table->addCell(null, $this->setColSpanCell(count($header))) - ->addText( - $this->anrTranslate('TxV'), - $this->boldFont, - $this->centerParagraph - ); + ->addText($this->anrTranslate('TxV'), $this->boldFont, $this->centerParagraph); $table->addRow(); $table->addCell(null, $this->rotate90TextCell) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); + ->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); $table->addCell(null, $this->whiteBigBorderTable); foreach ($header as $MxV) { - $table->addCell(Converter::cmToTwip(1), $this->whiteBigBorderTable) - ->addText( - $MxV, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1), $this->whiteBigBorderTable) + ->addText($MxV, $this->boldFont, $this->centerParagraph); } - for ($row = $impactsScale['min']; $row <= $impactsScale['max']; ++$row) { - $table->addRow(Converter::cmToTwip($size)); + for ($row = $impactsScale->getMin(); $row <= $impactsScale->getMax(); ++$row) { + $table->addRow(PhpWord\Shared\Converter::cmToTwip($size)); $table->addCell(null, $this->continueCell); - $table->addCell(Converter::cmToTwip(1), $this->whiteBigBorderTable) - ->addText( - $row, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1), $this->whiteBigBorderTable) + ->addText((string)$row, $this->boldFont, $this->centerParagraph); foreach ($header as $MxV) { $value = $MxV * $row; $style = array_merge($this->whiteBigBorderTable, $this->setBgColorCell($value)); - $table->addCell(null, $style) - ->addText( - $value, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(null, $style)->addText((string)$value, $this->boldFont, $this->centerParagraph); } } @@ -967,50 +708,39 @@ protected function generateInformationalRiskAcceptanceThresholdsTable($impactsSc /** * Generate Operational Risk Acceptance thresholds Table - * @return Table */ - protected function generateOperationalRiskImpactsTable( + private function generateOperationalRiskImpactsTable( $opRisksImpactsScales, $opRisksImpactsScaleMin, $opRisksImpactsScaleMax - ) { - $tableWord = new PhpWord(); + ): PhpWord\Element\Table { + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); $sizeColumn = 17 / count($opRisksImpactsScales); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Level'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Level'), $this->boldFont, $this->centerParagraph); foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $table->addCell(Converter::cmToTwip($sizeColumn), $this->grayCell) - ->addText( - _WT($opRiskImpactScale['label']), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip($sizeColumn), $this->grayCell) + ->addText(_WT($opRiskImpactScale['label']), $this->boldFont, $this->centerParagraph); } for ($row = $opRisksImpactsScaleMin; $row <= $opRisksImpactsScaleMax; ++$row) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(2.00), $this->restartAndTopCell) - ->addText( - $opRisksImpactsScales[0]['comments'][$row]['scaleValue'], + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndTopCell)->addText( + $opRisksImpactsScales[0]['comments'][$row]['scaleValue'], + $this->normalFont, + $this->centerParagraph + ); + foreach ($opRisksImpactsScales as $opRiskImpactScale) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip($sizeColumn), $this->restartAndTopCell)->addText( + _WT($opRiskImpactScale['comments'][$row]['comment']), $this->normalFont, - $this->centerParagraph + $this->leftParagraph ); - foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $table->addCell(Converter::cmToTwip($sizeColumn), $this->restartAndTopCell) - ->addText( - _WT($opRiskImpactScale['comments'][$row]['comment']), - $this->normalFont, - $this->leftParagraph - ); } } @@ -1018,59 +748,41 @@ protected function generateOperationalRiskImpactsTable( } /** - * Generate Operational Risk Likelihood Table - * @return Table + * Generate Operational Risk Likelihood Table. */ - protected function generateOperationalRiskLikelihoodTable($opRisksLikelihoodScale) + private function generateOperationalRiskLikelihoodTable($opRisksLikelihoodScale): PhpWord\Element\Table { - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Level'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(16.00), $this->grayCell) - ->addText( - $this->anrTranslate('Comment'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Level'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(16.00), $this->grayCell) + ->addText($this->anrTranslate('Comment'), $this->boldFont, $this->centerParagraph); foreach ($opRisksLikelihoodScale['comments'] as $comment) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $comment['scaleValue'], - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(16.00), $this->vAlignCenterCell) - ->addText( - _WT($comment['comment']), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($comment['scaleValue'], $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(16.00), $this->vAlignCenterCell) + ->addText(_WT($comment['comment']), $this->normalFont, $this->leftParagraph); } return $table; } /** - * Generate Operational Risk Acceptance thresholds Table - * @return Table + * Generate Operational Risk Acceptance thresholds table. */ - protected function generateOperationalRiskAcceptanceThresholdsTable( + private function generateOperationalRiskAcceptanceThresholdsTable( $opRisksImpactsScales, $opRisksLikelihoodScale, $opRisksImpactsScaleMin, $opRisksImpactsScaleMax - ) { - $tableWord = new PhpWord(); + ): PhpWord\Element\Table { + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->noBorderTable); @@ -1084,47 +796,26 @@ protected function generateOperationalRiskAcceptanceThresholdsTable( $table->addRow(); $table->addCell(null, $this->setColSpanCell(2)); $table->addCell(null, $this->setColSpanCell(count($header))) - ->addText( - $this->anrTranslate('Probability'), - $this->boldFont, - $this->centerParagraph - ); + ->addText($this->anrTranslate('Probability'), $this->boldFont, $this->centerParagraph); $table->addRow(); $table->addCell(null, $this->rotate90TextCell) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); + ->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); $table->addCell(null, $this->whiteBigBorderTable); - foreach ($header as $Prob) { - $table->addCell(Converter::cmToTwip($size), $this->whiteBigBorderTable) - ->addText( - $Prob, - $this->boldFont, - $this->centerParagraph - ); + foreach ($header as $prob) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip($size), $this->whiteBigBorderTable) + ->addText($prob, $this->boldFont, $this->centerParagraph); } for ($row = $opRisksImpactsScaleMin; $row <= $opRisksImpactsScaleMax; ++$row) { $impactValue = $opRisksImpactsScales[0]['comments'][$row]['scaleValue']; - $table->addRow(Converter::cmToTwip($size)); + $table->addRow(PhpWord\Shared\Converter::cmToTwip($size)); $table->addCell(null, $this->continueCell); - $table->addCell(Converter::cmToTwip($size), $this->whiteBigBorderTable) - ->addText( - $impactValue, - $this->boldFont, - $this->centerParagraph - ); - foreach ($header as $Prob) { - $value = $Prob * $impactValue; + $table->addCell(PhpWord\Shared\Converter::cmToTwip($size), $this->whiteBigBorderTable) + ->addText($impactValue, $this->boldFont, $this->centerParagraph); + foreach ($header as $prob) { + $value = $prob * $impactValue; $style = array_merge($this->whiteBigBorderTable, $this->setBgColorCell($value, false)); - $table->addCell(null, $style) - ->addText( - $value, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(null, $style)->addText((string)$value, $this->boldFont, $this->centerParagraph); } } @@ -1132,40 +823,40 @@ protected function generateOperationalRiskAcceptanceThresholdsTable( } /** - * Generate Trends Assessment Table - * @return Table + * Generate Trends Assessment Table. */ - protected function generateTrendAssessmentTable() + private function generateTrendAssessmentTable(): PhpWord\Element\Table { - $questions = $this->questionService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); - $questionsChoices = $this->questionChoiceService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); + $questions = $this->anrQuestionService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); + $questionsChoices = $this->anrQuestionChoiceService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->noBorderTable); // Fill in each row foreach ($questions as $question) { - $response = null; - if ($question['type'] == 1) { + $response = ''; + if ($question['type'] === 1) { // Simple text $response = $question['response']; } else { // Choice, either simple or multiple if ($question['multichoice']) { - $responseIds = json_decode($question['response'], true); + $responseIds = empty($question['response']) ? [] : json_decode($question['response'], true); $responses = []; - foreach ($questionsChoices as $choice) { - if (!is_null($responseIds) && array_search($choice['id'], $responseIds) !== false) { - $responses[] = '- ' . $choice['label' . $this->currentLangAnrIndex]; + if (!empty($responseIds)) { + foreach ($questionsChoices as $choice) { + if (in_array($choice['id'], $responseIds, true)) { + $responses[] = '- ' . $choice['label' . $this->currentLangAnrIndex]; + } } + $response = implode("\n", $responses); } - - $response = join("\n", $responses); } else { foreach ($questionsChoices as $choice) { - if ($choice['id'] == $question['response']) { + if ($choice['id'] === $question['response']) { $response = $choice['label' . $this->currentLangAnrIndex]; break; } @@ -1176,19 +867,15 @@ protected function generateTrendAssessmentTable() // no display question, if reply is empty if (!empty($response)) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(18.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(18.00), $this->vAlignCenterCell) ->addText( _WT($question['label' . $this->currentLangAnrIndex]), $this->boldFont, $this->leftParagraph ); $table->addRow(400); - $table->addCell(Converter::cmToTwip(18.00), $this->vAlignCenterCell) - ->addText( - _WT($response), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(18.00), $this->vAlignCenterCell) + ->addText(_WT($response), $this->normalFont, $this->leftParagraph); } } @@ -1196,152 +883,102 @@ protected function generateTrendAssessmentTable() } /** - * Generate Interviews Table - * @return Table + * Generate Interviews Table. */ - protected function generateInterviewsTable() + private function generateInterviewsTable(): PhpWord\Element\Table { $interviews = $this->interviewService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); if (count($interviews)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate("Date"), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate("Department / People"), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(9.00), $this->grayCell) - ->addText( - $this->anrTranslate("Contents"), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate("Date"), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate("Department / People"), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(9.00), $this->grayCell) + ->addText($this->anrTranslate("Contents"), $this->boldFont, $this->centerParagraph); } // Fill in each row foreach ($interviews as $interview) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($interview['date']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($interview['service']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(9.00), $this->vAlignCenterCell) - ->addText( - _WT($interview['content']), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($interview['date']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($interview['service']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(9.00), $this->vAlignCenterCell) + ->addText(_WT($interview['content']), $this->normalFont, $this->leftParagraph); } return $table; } /** - * Generate Threat or Vulnerability scale table - * @param array $scale - * @param array $comments - * @return Table + * Generate Threat or Vulnerability scale table. */ - protected function generateThreatOrVulnerabilityScaleTable($scale, $comments) + private function generateThreatOrVulnerabilityScaleTable(Entity\Scale $scale): PhpWord\Element\Table { - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Level'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(16.00), $this->grayCell) - ->addText( - $this->anrTranslate('Comment'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Level'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(16.00), $this->grayCell) + ->addText($this->anrTranslate('Comment'), $this->boldFont, $this->centerParagraph); // Fill in each row - for ($row = $scale['min']; $row <= $scale['max']; ++$row) { + for ($scaleIndex = $scale->getMin(); $scaleIndex <= $scale->getMax(); ++$scaleIndex) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $row, - $this->normalFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($scaleIndex, $this->normalFont, $this->centerParagraph); // Find the appropriate comment $commentText = ''; - foreach ($comments as $comment) { - if ($comment['scaleIndex'] == $row) { - $commentText = $comment['comment' . $this->currentLangAnrIndex]; + foreach ($scale->getScaleComments() as $scaleComment) { + if ($scaleComment->getScaleIndex() === $scaleIndex) { + $commentText = $scaleComment->getComment($this->currentLangAnrIndex); break; } } - $table->addCell(Converter::cmToTwip(16.00), $this->vAlignCenterCell) - ->addText( - _WT($commentText), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(16.00), $this->vAlignCenterCell) + ->addText(_WT($commentText), $this->normalFont, $this->leftParagraph); } return $table; } /** - * Generate Current Risk Map - * @param string $type - * @return string + * Generate Current Risk Map. */ - protected function generateCurrentRiskMap($type = 'real') + private function generateCurrentRiskMap(string $type = 'real'): string { - $cartoRisk = ($type == 'real') ? - $this->cartoRiskService->getCartoReal($this->anr->getId()) : - $this->cartoRiskService->getCartoTargeted($this->anr->getId()); + $cartoRisk = $type === 'real' + ? $this->cartoRiskService->getCartoReal($this->anr) + : $this->cartoRiskService->getCartoTargeted($this->anr); - // Generate risks table - $tableWord = new PhpWord(); - $section = $tableWord->addSection(); + // Generate risks table + $tableWord = new PhpWord\PhpWord(); + $section = $tableWord->addSection(); if (!empty($cartoRisk['riskInfo']['counters'])) { - $section->addText( - $this->anrTranslate('Information risks'), - $this->boldFont, - ['indent' => 0.5] - ); + $section->addText($this->anrTranslate('Information risks'), $this->boldFont, ['indent' => 0.5]); - $params = [ + $params = [ 'riskType' => 'riskInfo', 'axisX' => 'MxV', 'axisY' => 'Impact', 'labelAxisX' => 'TxV', 'thresholds' => [ - $this->anr->seuil1, - $this->anr->seuil2 + $this->anr->getSeuil1(), + $this->anr->getSeuil2(), ], ]; $section = $this->generateCartographyMap($cartoRisk, $section, $params); @@ -1352,31 +989,32 @@ protected function generateCurrentRiskMap($type = 'real') $this->boldFont, ['indent' => 0.5] ); - $params = [ + $params = [ 'riskType' => 'riskOp', 'axisX' => 'Likelihood', 'axisY' => 'OpRiskImpact', 'labelAxisX' => 'Probability', 'thresholds' => [ - $this->anr->seuilRolf1, - $this->anr->seuilRolf2 + $this->anr->getSeuilRolf1(), + $this->anr->getSeuilRolf2(), ], ]; - $section = $this->generateCartographyMap($cartoRisk, $section, $params); + $this->generateCartographyMap($cartoRisk, $section, $params); } - return $this->getWordXmlFromWordObject($tableWord); + return $this->getWordXmlFromWordObject($tableWord); } /** * Generate Cartography Map + * * @param $data * @param object $section - * @param object $params + * @param array $params * * @return object */ - protected function generateCartographyMap($data, $section, $params) + private function generateCartographyMap($data, $section, $params) { $axisX = $data[$params['axisX']]; $axisY = $data[$params['axisY']]; @@ -1386,30 +1024,18 @@ protected function generateCartographyMap($data, $section, $params) $size = 0.75; $table = $section->addTable($this->noBorderTable); - $table->addRow(Converter::cmToTwip($size)); + $table->addRow(PhpWord\Shared\Converter::cmToTwip($size)); $table->addCell(null, $this->setColSpanCell(2)); $table->addCell(null, $this->setColSpanCell(count($axisX))) - ->addText( - $this->anrTranslate($labelAxisX), - $this->boldFont, - $this->centerParagraph - ); - $table->addRow(Converter::cmToTwip($size)); + ->addText($this->anrTranslate($labelAxisX), $this->boldFont, $this->centerParagraph); + $table->addRow(PhpWord\Shared\Converter::cmToTwip($size)); $table->addCell(null, $this->rotate90TextCell) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip($size), $this->whiteBigBorderTable); + ->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip($size), $this->whiteBigBorderTable); foreach ($axisX as $x) { - $table->addCell(Converter::cmToTwip($size), $this->whiteBigBorderTable) - ->addText( - $x, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip($size), $this->whiteBigBorderTable) + ->addText($x, $this->boldFont, $this->centerParagraph); } //row @@ -1417,14 +1043,10 @@ protected function generateCartographyMap($data, $section, $params) $nbMedium = 0; $nbHigh = 0; foreach ($axisY as $y) { - $table->addRow(Converter::cmToTwip($size)); + $table->addRow(PhpWord\Shared\Converter::cmToTwip($size)); $table->addCell(null, $this->continueCell); - $table->addCell(Converter::cmToTwip($size), $this->whiteBigBorderTable) - ->addText( - $y, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip($size), $this->whiteBigBorderTable) + ->addText($y, $this->boldFont, $this->centerParagraph); foreach ($axisX as $x) { $value = $x * $y; @@ -1443,108 +1065,90 @@ protected function generateCartographyMap($data, $section, $params) } else { $style['BgColor'] = 'F0F7B2'; } + } elseif ($value <= $thresholds[1]) { + $style['BgColor'] = 'FFBC1C'; + if ($result) { + $nbMedium += $result; + } else { + $style['BgColor'] = 'FCDD94'; + } } else { - if ($value <= $thresholds[1]) { - $style['BgColor'] = 'FFBC1C'; - if ($result) { - $nbMedium += $result; - } else { - $style['BgColor'] = 'FCDD94'; - } + $style['BgColor'] = 'FD661F'; + if ($result) { + $nbHigh += $result; } else { - $style['BgColor'] = 'FD661F'; - if ($result) { - $nbHigh += $result; - } else { - $style['BgColor'] = 'FCB28F'; - } + $style['BgColor'] = 'FCB28F'; } } - $table->addCell(Converter::cmToTwip($size), $style) - ->addText( - $result, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip($size), $style) + ->addText($result, $this->boldFont, $this->centerParagraph); } } //legend $maxSize = 7; $total = $nbLow + $nbMedium + $nbHigh; - $lowSize = ($total) ? ($maxSize * $nbLow) / $total : 0; - $mediumSize = ($total) ? ($maxSize * $nbMedium) / $total : 0; - $highSize = ($total) ? ($maxSize * $nbHigh) / $total : 0; + $lowSize = $total ? $maxSize * $nbLow / $total : 0; + $mediumSize = $total ? $maxSize * $nbMedium / $total : 0; + $highSize = $total ? $maxSize * $nbHigh / $total : 0; $section->addTextBreak(1); $tableLegend = $section->addTable(); - $tableLegend->addRow(Converter::cmToTwip(0.1)); - $tableLegend->addCell(Converter::cmToTwip(0.5), $this->continueCell); - $tableLegend->addCell(Converter::cmToTwip(5), $this->whiteBigBorderTable) - ->addText( - $nbLow . ' ' . $this->anrTranslate('Low risks'), - $this->boldFont, - $this->leftParagraph - ); + $tableLegend->addRow(PhpWord\Shared\Converter::cmToTwip(0.1)); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip(0.5), $this->continueCell); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip(5), $this->whiteBigBorderTable) + ->addText($nbLow . ' ' . $this->anrTranslate('Low risks'), $this->boldFont, $this->leftParagraph); if ($lowSize > 0) { $style = array_merge( $this->whiteBigBorderTable, ['BgColor' => 'D6F107', 'BorderTopSize' => 0, 'BorderBottomSize' => 30] ); unset($style['BorderSize']); - $tableLegend->addCell(Converter::cmToTwip($lowSize), $style); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip($lowSize), $style); } - if (($maxSize - $lowSize) != 0) { + if (($maxSize - $lowSize) !== 0) { $style['BgColor'] = 'F0F7B2'; - $tableLegend->addCell(Converter::cmToTwip($maxSize - $lowSize), $style); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip($maxSize - $lowSize), $style); } $tableLegend = $section->addTable(); - $tableLegend->addRow(Converter::cmToTwip(0.1)); - $tableLegend->addCell(Converter::cmToTwip(0.5), $this->continueCell); - $tableLegend->addCell(Converter::cmToTwip(5), $this->whiteBigBorderTable) - ->addText( - $nbMedium . ' ' . $this->anrTranslate('Medium risks'), - $this->boldFont, - $this->leftParagraph - ); + $tableLegend->addRow(PhpWord\Shared\Converter::cmToTwip(0.1)); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip(0.5), $this->continueCell); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip(5), $this->whiteBigBorderTable) + ->addText($nbMedium . ' ' . $this->anrTranslate('Medium risks'), $this->boldFont, $this->leftParagraph); if ($mediumSize > 0) { $style = array_merge( $this->whiteBigBorderTable, ['BgColor' => 'FFBC1C', 'BorderTopSize' => 50, 'BorderBottomSize' => 30] ); unset($style['BorderSize']); - $tableLegend->addCell(Converter::cmToTwip($mediumSize), $style); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip($mediumSize), $style); } - if (($maxSize - $mediumSize) != 0) { + if (($maxSize - $mediumSize) !== 0) { $style['BgColor'] = 'FCDD94'; - $tableLegend->addCell(Converter::cmToTwip($maxSize - $mediumSize), $style); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip($maxSize - $mediumSize), $style); } $tableLegend = $section->addTable(); - $tableLegend->addRow(Converter::cmToTwip(0.1)); - $tableLegend->addCell(Converter::cmToTwip(0.5), $this->continueCell); - $tableLegend->addCell(Converter::cmToTwip(5), $this->whiteBigBorderTable) - ->addText( - $nbHigh . ' ' . $this->anrTranslate('High risks'), - $this->boldFont, - $this->leftParagraph - ); + $tableLegend->addRow(PhpWord\Shared\Converter::cmToTwip(0.1)); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip(0.5), $this->continueCell); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip(5), $this->whiteBigBorderTable) + ->addText($nbHigh . ' ' . $this->anrTranslate('High risks'), $this->boldFont, $this->leftParagraph); if ($highSize > 0) { $style = array_merge( $this->whiteBigBorderTable, ['BgColor' => 'FD661F', 'BorderTopSize' => 50, 'BorderBottomSize' => 30] ); unset($style['BorderSize']); - $tableLegend->addCell(Converter::cmToTwip($highSize), $style); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip($highSize), $style); } - if (($maxSize - $highSize) != 0) { + if (($maxSize - $highSize) !== 0) { $style['BgColor'] = 'FCB28F'; - $tableLegend->addCell(Converter::cmToTwip($maxSize - $highSize), $style); + $tableLegend->addCell(PhpWord\Shared\Converter::cmToTwip($maxSize - $highSize), $style); } return $section; @@ -1552,14 +1156,14 @@ protected function generateCartographyMap($data, $section, $params) /** * Generates the risks graph that is included in the model - * @return array An array with the path and details of the generated canvas + * @return PhpWord\Element\Chart An array with the path and details of the generated canvas */ - protected function generateRisksGraph($infoRisk = true) + private function generateRisksGraph($infoRisk = true): PhpWord\Element\Chart { - $this->cartoRiskService->buildListScalesAndHeaders($this->anr->getId()); - [$counters, $distrib] = $infoRisk ? - $this->cartoRiskService->getCountersRisks('raw') : - $this->cartoRiskService->getCountersOpRisks('raw') ; + $this->cartoRiskService->buildListScalesAndHeaders($this->anr); + [$counters, $distrib] = $infoRisk + ? $this->cartoRiskService->getCountersRisks($this->anr) + : $this->cartoRiskService->getCountersOpRisks($this->anr); $categories = [ $this->anrTranslate('Low risks'), @@ -1573,27 +1177,19 @@ protected function generateRisksGraph($infoRisk = true) $distrib[2] ?? 0, ]; - $PhpWord = new PhpWord(); - $section = $PhpWord->addSection(); - $chart = $section->addChart( - 'column', - $categories, - $series, - $this->barChart - ); - - return $chart; + return (new PhpWord\PhpWord())->addSection()->addChart('column', $categories, $series, $this->barChart); } /** * Generate the audit table data * @return mixed|string The generated WordXml data */ - protected function generateTableAudit() + private function generateTableAudit() { $instanceRisks = $this->instanceRiskTable->findByAnrAndOrderByParams($this->anr, ['ir.cacheMaxRisk' => 'DESC']); - $mem_risks = $globalObject = []; + $globalObject = []; + $mem_risks = $globalObject; $maxLevelDeep = 1; foreach ($instanceRisks as $instanceRisk) { @@ -1606,7 +1202,7 @@ protected function generateTableAudit() $key = "o-" . $objectUuid; if (!isset($mem_risks[$key])) { $mem_risks[$key] = [ - 'ctx' => $instance->{'getName' . $this->currentLangAnrIndex}() + 'ctx' => $instance->getName($this->currentLangAnrIndex) . ' (' . $this->anrTranslate('Global') . ')', 'global' => true, 'risks' => [], @@ -1617,7 +1213,7 @@ protected function generateTableAudit() $key = "i-" . $instance->getId(); if (!isset($mem_risks[$key])) { $asc = $instance->getHierarchyArray(); - $levelTree = \count($asc); + $levelTree = count($asc); if ($levelTree > $maxLevelDeep) { $maxLevelDeep = $levelTree; } @@ -1669,7 +1265,7 @@ protected function generateTableAudit() 'riskA' => $instanceRisk->getThreat()->getAvailability() === 0 ? null : $instanceRisk->getRiskAvailability(), - 'kindOfMeasure' => $instanceRisk->getKindOfMeasure(), + 'treatmentName' => $instanceRisk->getTreatmentName(), 'targetRisk' => $instanceRisk->getCacheTargetedRisk(), ]; } @@ -1684,179 +1280,103 @@ protected function generateTableAudit() $maxLevelTitle = $maxLevelDeep === 1 ? $maxLevelDeep : $maxLevelDeep - 1; $title = array_fill(0, $maxLevelDeep, null); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); for ($i = 0; $i < $maxLevelDeep + 1; $i++) { $tableWord->addTitleStyle($i + 3, $this->titleFont); } - if (in_array('true', $global)) { - $section->addTitle( - $this->anrTranslate('Global assets'), - 3 - ); + if (in_array('true', $global, true)) { + $section->addTitle($this->anrTranslate('Global assets'), 3); } foreach ($mem_risks as $data) { if (empty($data['tree'])) { - $section->addTitle( - _WT($data['ctx']), - 4 - ); + $section->addTitle(_WT($data['ctx']), 4); $table = $section->addTable($this->borderTable); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, '444444')) - ->addText( - $this->anrTranslate('Impact'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.70), $this->setColSpanCell(2, '444444')) - ->addText( - $this->anrTranslate('Threat'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(10.70), $this->setColSpanCell(3, '444444')) - ->addText( - $this->anrTranslate('Vulnerability'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, '444444')) - ->addText( - $this->anrTranslate('Current risk'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) - ->addText( - $this->anrTranslate('Treatment'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->whiteFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->setColSpanCell(3, '444444')) + ->addText($this->anrTranslate('Impact'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.70), $this->setColSpanCell(2, '444444')) + ->addText($this->anrTranslate('Threat'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.70), $this->setColSpanCell(3, '444444')) + ->addText($this->anrTranslate('Vulnerability'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->setColSpanCell(3, '444444')) + ->addText($this->anrTranslate('Current risk'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) + ->addText($this->anrTranslate('Treatment'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) + ->addText($this->anrTranslate('Residual risk'), $this->whiteFont, $this->centerParagraph); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'C', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'I', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('A'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->blackCell) - ->addText( - $this->anrTranslate('Label'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->blackCell) - ->addText( - $this->anrTranslate('Label'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->blackCell) - ->addText( - $this->anrTranslate('Existing controls'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('Qualif.'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'C', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'I', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('A'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('C', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('I', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('A'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->blackCell) + ->addText($this->anrTranslate('Label'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('Prob.'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->blackCell) + ->addText($this->anrTranslate('Label'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->blackCell) + ->addText($this->anrTranslate('Existing controls'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('Qualif.'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('C', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('I', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('A'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); } else { - for ($i = 0; $i < count($data['tree']); $i++) { - if ($i <= $maxLevelTitle - 1 && $title[$i] != $data['tree'][$i]['id']) { - $section->addTitle( - _WT($data['tree'][$i]['name' . $this->currentLangAnrIndex]), - $i + 3 - ); + $treeNum = count($data['tree']); + for ($i = 0; $i < $treeNum; $i++) { + if ($i <= $maxLevelTitle - 1 && $title[$i] !== $data['tree'][$i]['id']) { + $section->addTitle(_WT($data['tree'][$i]['name' . $this->currentLangAnrIndex]), $i + 3); $title[$i] = $data['tree'][$i]['id']; - if ($maxLevelTitle == count($data['tree']) && empty($data['risks'])) { + if ($maxLevelTitle === $treeNum && empty($data['risks'])) { $data['risks'] = true; } - if ($i == count($data['tree']) - 1 && !empty($data['risks'])) { + if ($i === ($treeNum - 1) && !empty($data['risks'])) { $section->addTextBreak(); $table = $section->addTable($this->borderTable); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, '444444')) - ->addText( - $this->anrTranslate('Impact'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.70), $this->setColSpanCell(2, '444444')) - ->addText( - $this->anrTranslate('Threat'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(10.70), $this->setColSpanCell(3, '444444')) - ->addText( - $this->anrTranslate('Vulnerability'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, '444444')) - ->addText( - $this->anrTranslate('Current risk'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(2.10), + $this->setColSpanCell(3, '444444') + )->addText($this->anrTranslate('Impact'), $this->whiteFont, $this->centerParagraph); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(5.70), + $this->setColSpanCell(2, '444444') + )->addText($this->anrTranslate('Threat'), $this->whiteFont, $this->centerParagraph); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(10.70), + $this->setColSpanCell(3, '444444') + )->addText( + $this->anrTranslate('Vulnerability'), + $this->whiteFont, + $this->centerParagraph + ); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(2.10), + $this->setColSpanCell(3, '444444') + )->addText( + $this->anrTranslate('Current risk'), + $this->whiteFont, + $this->centerParagraph + ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Treatment'), $this->whiteFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Residual risk'), $this->whiteFont, @@ -1864,176 +1384,82 @@ protected function generateTableAudit() ); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'C', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'I', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('A'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->blackCell) - ->addText( - $this->anrTranslate('Label'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->blackCell) - ->addText( - $this->anrTranslate('Label'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->blackCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('C', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('I', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('A'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->blackCell) + ->addText($this->anrTranslate('Label'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('Prob.'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->blackCell) + ->addText($this->anrTranslate('Label'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->blackCell) ->addText( $this->anrTranslate('Existing controls'), $this->whiteFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('Qualif.'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'C', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - 'I', - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->blackCell) - ->addText( - $this->anrTranslate('A'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('Qualif.'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('C', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText('I', $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->blackCell) + ->addText($this->anrTranslate('A'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); } } } } if (!empty($data['risks']) && $data['risks'] !== true) { - if ($data['global'] == false) { + if ($data['global'] === false) { $table = $section->addTable($this->borderTable); $table->addRow(400); - $table->addCell(Converter::cmToTwip(19.00), $this->setColSpanCell(13, 'DFDFDF')) - ->addText( - _WT($data['ctx']), - $this->boldFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(19.00), $this->setColSpanCell(13, 'DFDFDF')) + ->addText(_WT($data['ctx']), $this->boldFont, $this->leftParagraph); } foreach ($data['risks'] as $r) { foreach ($r as $key => $value) { - if ($value == -1) { + if ($value === -1) { $r[$key] = '-'; } } $table->addRow(400); - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['impactC'], - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['impactI'], - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['impactA'], - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($r['threat']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['threatRate'], - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($r['vulnerability']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($r['comment']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['vulRate'], - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->setBgColorCell($r['riskC'])) - ->addText( - $r['riskC'], - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->setBgColorCell($r['riskI'])) - ->addText( - $r['riskI'], - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->setBgColorCell($r['riskA'])) - ->addText( - $r['riskA'], - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $this->getKindfofMeasureLabel($r['kindOfMeasure']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['targetRisk'])) - ->addText( - $r['targetRisk'], - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['impactC'], $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['impactI'], $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['impactA'], $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($r['threat']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['threatRate'], $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($r['vulnerability']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($r['comment']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['vulRate'], $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->setBgColorCell($r['riskC'])) + ->addText($r['riskC'], $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->setBgColorCell($r['riskI'])) + ->addText($r['riskI'], $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->setBgColorCell($r['riskA'])) + ->addText($r['riskA'], $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($r['treatmentName'], $this->normalFont, $this->leftParagraph); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($r['targetRisk']) + )->addText($r['targetRisk'], $this->boldFont, $this->centerParagraph); } } } @@ -2060,7 +1486,7 @@ private function generateTableAuditOp() $instance = $operationalInstanceRisk->getInstance(); if (!isset($lst[$instance->getId()])) { $ascendants = $instance->getHierarchyArray(); - $levelTree = \count($ascendants); + $levelTree = count($ascendants); if ($levelTree > $maxLevelDeep) { $maxLevelDeep = $levelTree; } @@ -2069,7 +1495,7 @@ private function generateTableAuditOp() $lst[$instance->getId()] = [ 'tree' => $ascendants, 'path' => $this->getInstancePathFromHierarchy($ascendants), - 'parent' => $parentInstance ? $parentInstance->getId() : null, + 'parent' => $parentInstance?->getId(), 'position' => $instance->getPosition(), 'risks' => [], ]; @@ -2113,7 +1539,7 @@ private function generateTableAuditOp() 'scales' => $scalesData, 'comment' => $operationalInstanceRisk->getComment(), 'targetedRisk' => $operationalInstanceRisk->getCacheTargetedRisk(), - 'kindOfMeasure' => $operationalInstanceRisk->getKindOfMeasure(), + 'treatmentName' => $operationalInstanceRisk->getTreatmentName(), ]; } $tree = []; @@ -2127,7 +1553,7 @@ private function generateTableAuditOp() } $lst = []; - usort($tree, function ($a, $b) { + usort($tree, static function ($a, $b) { return $a['position'] <=> $b['position']; }); foreach ($tree as $branch) { @@ -2137,74 +1563,68 @@ private function generateTableAuditOp() } if (!empty($lst)) { - $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr->getId()); - $opRisksImpactsScaleType = array_values(array_filter($opRisksAllScales, function ($scale) { - return $scale['type'] == 1; - })); + $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr); + $opRisksImpactsScaleType = array_values( + array_filter($opRisksAllScales, function ($scale) { + return $scale['type'] === 1; + }) + ); $opRisksImpactsScales = array_filter($opRisksImpactsScaleType[0]['scaleTypes'], function ($scale) { - return $scale['isHidden'] == false; + return $scale['isHidden'] === false; }); $sizeCellImpact = count($opRisksImpactsScales) * 0.70; - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $maxLevelDeep = ($maxLevelDeep <= 4 ? $maxLevelDeep : 4); - for ($i=0; $i < $maxLevelDeep; $i++) { + for ($i = 0; $i < $maxLevelDeep; $i++) { $tableWord->addTitleStyle($i + 3, $this->titleFont); } - $maxLevelTitle = ($maxLevelDeep == 1 ? $maxLevelDeep : $maxLevelDeep - 1); + $maxLevelTitle = ($maxLevelDeep === 1 ? $maxLevelDeep : $maxLevelDeep - 1); $title = array_fill(0, $maxLevelDeep, null); foreach ($lst as $data) { - for ($i = 0; $i < count($data['tree']); $i++) { - if ($i <= $maxLevelTitle - 1 && $title[$i] != $data['tree'][$i]['id']) { + $treeElementsNum = count($data['tree']); + for ($i = 0; $i < $treeElementsNum; $i++) { + if ($i <= $maxLevelTitle - 1 && $title[$i] !== $data['tree'][$i]['id']) { $section->addTitle( _WT($data['tree'][$i]['name' . $this->currentLangAnrIndex]), $i + 3 ); $title[$i] = $data['tree'][$i]['id']; - if ($maxLevelTitle == count($data['tree']) && empty($data['risks'])) { + if (empty($data['risks']) && $maxLevelTitle === $treeElementsNum) { $data['risks'] = true; } - if ($i == count($data['tree']) - 1 && !empty($data['risks'])) { + if (!empty($data['risks']) && $i === ($treeElementsNum - 1)) { $section->addTextBreak(); $table = $section->addTable($this->borderTable); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(10.00), $this->restartAndBlackCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Risk description'), $this->whiteFont, $this->centerParagraph ); - if ($this->anr->showRolfBrut == 1) { + if ($this->anr->showRolfBrut()) { $table->addCell( - Converter::cmToTwip(5.50), + PhpWord\Shared\Converter::cmToTwip(5.50), $this->setColSpanCell(2 + count($opRisksImpactsScales), '444444') - ) - ->addText( - $this->anrTranslate('Inherent risk'), - $this->whiteFont, - $this->centerParagraph - ); + )->addText( + $this->anrTranslate('Inherent risk'), + $this->whiteFont, + $this->centerParagraph + ); } $table->addCell( - Converter::cmToTwip(15.00), + PhpWord\Shared\Converter::cmToTwip(15.00), $this->setColSpanCell(3 + count($opRisksImpactsScales), '444444') ) - ->addText( - $this->anrTranslate('Net risk'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.00), $this->restartAndBlackCell) - ->addText( - $this->anrTranslate('Treatment'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.00), $this->restartAndBlackCell) + ->addText($this->anrTranslate('Net risk'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndBlackCell) + ->addText($this->anrTranslate('Treatment'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Residual risk'), $this->whiteFont, @@ -2212,222 +1632,162 @@ private function generateTableAuditOp() ); $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(10.00), $this->continueAndBlackCell); - if ($this->anr->showRolfBrut == 1) { - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->whiteFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->continueAndBlackCell); + if ($this->anr->showRolfBrut()) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) + ->addText($this->anrTranslate('Prob.'), $this->whiteFont); $table->addCell( - Converter::cmToTwip($sizeCellImpact), + PhpWord\Shared\Converter::cmToTwip($sizeCellImpact), $this->setColSpanCell(count($opRisksImpactsScales), '444444') - ) - ->addText( - $this->anrTranslate('Impact'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) + )->addText($this->anrTranslate('Impact'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Current risk'), $this->whiteFont, $this->centerParagraph ); } - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->whiteFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) + ->addText($this->anrTranslate('Prob.'), $this->whiteFont, $this->centerParagraph); $table->addCell( - Converter::cmToTwip($sizeCellImpact), + PhpWord\Shared\Converter::cmToTwip($sizeCellImpact), $this->setColSpanCell(count($opRisksImpactsScales), '444444') - ) - ->addText( - $this->anrTranslate('Impact'), - $this->whiteFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndBlackCell) + )->addText($this->anrTranslate('Impact'), $this->whiteFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Current risk'), $this->whiteFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(8.00), $this->restartAndBlackCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->restartAndBlackCell) ->addText( $this->anrTranslate('Existing controls'), $this->whiteFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(2.00), $this->continueAndBlackCell); - $table->addCell(Converter::cmToTwip(2.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndBlackCell); + + $table->addRow(PhpWord\Shared\Converter::cmToTwip(1.00), $this->tblHeader); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->continueAndBlackCell); - $table->addRow(Converter::cmToTwip(1.00), $this->tblHeader); - $table->addCell(Converter::cmToTwip(10.00), $this->continueAndBlackCell); - if ($this->anr->showRolfBrut == 1) { - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); + if ($this->anr->showRolfBrut()) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); foreach ($opRisksImpactsScales as $opRiskImpactScale) { $label = mb_substr(_WT($opRiskImpactScale['label']), 0, 3) . '.'; $table->addCell( - Converter::cmToTwip(0.70), + PhpWord\Shared\Converter::cmToTwip(0.70), array_merge($this->rotate90TextCell, ['bgcolor' => '444444']) ) - ->addText( - $label, - $this->whiteFont, - $this->verticalCenterParagraph - ); + ->addText($label, $this->whiteFont); } - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); } - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); foreach ($opRisksImpactsScales as $opRiskImpactScale) { $label = mb_substr(_WT($opRiskImpactScale['label']), 0, 3) . '.'; $table->addCell( - Converter::cmToTwip(0.70), + PhpWord\Shared\Converter::cmToTwip(0.70), array_merge($this->rotate90TextCell, ['bgcolor' => '444444']) ) - ->addText( - $label, - $this->whiteFont, - $this->verticalCenterParagraph - ); + ->addText($label, $this->whiteFont, $this->verticalCenterParagraph); } - $table->addCell(Converter::cmToTwip(1.00), $this->continueAndBlackCell); - $table->addCell(Converter::cmToTwip(8.00), $this->continueAndBlackCell); - $table->addCell(Converter::cmToTwip(2.00), $this->continueAndBlackCell); - $table->addCell(Converter::cmToTwip(2.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndBlackCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndBlackCell); } } } if (!empty($data['risks']) && $data['risks'] !== true) { $styleCell = $this->setColSpanCell(6 + count($opRisksImpactsScales), 'DFDFDF'); - if ($this->anr->showRolfBrut == 1) { + if ($this->anr->showRolfBrut()) { $styleCell = $this->setColSpanCell(8 + count($opRisksImpactsScales) * 2, 'DFDFDF'); } $table = $section->addTable($this->borderTable); $table->addRow(400); - $table->addCell(Converter::cmToTwip(19.00), $styleCell) - ->addText( - _WT($data['path']), - $this->boldFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(19.00), $styleCell) + ->addText(_WT($data['path']), $this->boldFont, $this->leftParagraph); foreach ($data['risks'] as $r) { - if (!empty($data['risks'])) { - foreach ($r as $key => $value) { - if ($value == -1) { - $r[$key] = '-'; - } + foreach ($r as $key => $value) { + if ($value === -1) { + $r[$key] = '-'; } - $table->addRow(400); - $table->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) - ->addText( - _WT($r['label']), - $this->normalFont, - $this->leftParagraph - ); - if ($this->anr->showRolfBrut == 1) { - $table->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $r['brutProb'], - $this->normalFont, - $this->centerParagraph - ); - foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) + } + $table->addRow(400); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) + ->addText(_WT($r['label']), $this->normalFont, $this->leftParagraph); + if ($this->anr->showRolfBrut()) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($r['brutProb'], $this->normalFont, $this->centerParagraph); + foreach ($opRisksImpactsScales as $opRiskImpactScale) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) ->addText( $r['scales'][$opRiskImpactScale['id']]['brutValue'], $this->normalFont, $this->centerParagraph ); - } - $table->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['brutRisk'], false)) - ->addText( - $r['brutRisk'], - $this->boldFont, - $this->centerParagraph - ); } - $table->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $r['netProb'], - $this->normalFont, - $this->centerParagraph - ); - foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $table->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($r['brutRisk'], false) + )->addText($r['brutRisk'], $this->boldFont, $this->centerParagraph); + } + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($r['netProb'], $this->normalFont, $this->centerParagraph); + foreach ($opRisksImpactsScales as $opRiskImpactScale) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) ->addText( $r['scales'][$opRiskImpactScale['id']]['netValue'], $this->normalFont, $this->centerParagraph ); - } - $table->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['netRisk'], false)) - ->addText( - $r['netRisk'], - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(8.00), $this->vAlignCenterCell) - ->addText( - _WT($r['comment']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $this->getKindfofMeasureLabel($r['kindOfMeasure']), - $this->normalFont, - $this->leftParagraph - ); - $targetedRisk = $r['targetedRisk'] == '-' ? $r['netRisk'] : $r['targetedRisk']; - $table->addCell(Converter::cmToTwip(2.00), $this->setBgColorCell($targetedRisk, false)) - ->addText( - $targetedRisk, - $this->boldFont, - $this->centerParagraph - ); } + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($r['netRisk'], false) + )->addText($r['netRisk'], $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->vAlignCenterCell) + ->addText(_WT($r['comment']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($r['treatmentName'], $this->normalFont, $this->leftParagraph); + $targetedRisk = $r['targetedRisk'] === '-' ? $r['netRisk'] : $r['targetedRisk']; + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(2.00), + $this->setBgColorCell($targetedRisk, false) + )->addText($targetedRisk, $this->boldFont, $this->centerParagraph); } } } + return $this->getWordXmlFromWordObject($tableWord); } } /** - * Generates Word-compliant HTML for the risks distribution paragraph + * Generates Word-compliant HTML for the risks' distribution paragraph. + * * @return string HTML data that can be converted into WordXml data */ - protected function getRisksDistribution($infoRisk = true) + private function getRisksDistribution($infoRisk = true) { - $this->cartoRiskService->buildListScalesAndHeaders($this->anr->getId()); - [$counters, $distrib] = $infoRisk ? - $this->cartoRiskService->getCountersRisks('raw') : - $this->cartoRiskService->getCountersOpRisks('raw') ; + $this->cartoRiskService->buildListScalesAndHeaders($this->anr); + [$counters, $distrib] = $infoRisk + ? $this->cartoRiskService->getCountersRisks($this->anr) + : $this->cartoRiskService->getCountersOpRisks($this->anr); - $colors = array(0, 1, 2); $sum = 0; - - foreach ($colors as $c) { - if (!isset($distrib[$c])) { - $distrib[$c] = 0; + foreach ([0, 1, 2] as $color) { + if (!isset($distrib[$color])) { + $distrib[$color] = 0; } - $sum += $distrib[$c]; + $sum += $distrib[$color]; } - $intro = sprintf( - $this->anrTranslate( - "The list of risks addressed is provided as an attachment. It lists %d risk(s) of which:" - ), - $sum - ); + $intro = sprintf($this->anrTranslate( + "The list of risks addressed is provided as an attachment. It lists %d risk(s) of which:" + ), $sum); return $intro . "  - " . @@ -2447,37 +1807,38 @@ protected function getRisksDistribution($infoRisk = true) } /** - * Generates the Risks by kind of treatment + * Generates the Risks by kind of treatment. + * * @return mixed|string The WordXml data generated */ - protected function generateRisksByKindOfTreatment() + private function generateRisksByKindOfMeasure() { $result = null; - $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr->getId()); - $opRisksImpactsScaleType = array_values(array_filter($opRisksAllScales, function ($scale) { - return $scale['type'] == 1; - })); - $opRisksImpactsScales = array_filter($opRisksImpactsScaleType[0]['scaleTypes'], function ($scale) { - return $scale['isHidden'] == false; + $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr); + $opRisksImpactsScaleType = array_values( + array_filter($opRisksAllScales, static function ($scale) { + return $scale['type'] === OperationalRiskScaleSuperClass::TYPE_IMPACT; + }) + ); + $opRisksImpactsScales = array_filter($opRisksImpactsScaleType[0]['scaleTypes'], static function ($scale) { + return $scale['isHidden'] === false; }); $sizeCellImpact = count($opRisksImpactsScales) * 0.70; - for ($i = 1; $i <= 4; $i++) { - $risksByTreatment = $this->get('anrInstanceRiskService') - ->getInstanceRisks( - $this->anr->getId(), - null, - ['limit' => -1, 'order' => 'maxRisk', 'order_direction' => 'desc', 'kindOfMeasure' => $i] - ); - $risksOpByTreatment = $this->get('anrInstanceRiskOpService') - ->getOperationalRisks( - $this->anr->getId(), - null, - ['limit' => -1, 'order' => 'cacheNetRisk', 'order_direction' => 'desc', 'kindOfMeasure' => $i] - ); + for ($i = InstanceRiskSuperClass::KIND_REDUCTION; $i <= InstanceRiskSuperClass::KIND_SHARED; $i++) { + $risksByTreatment = $this->anrInstanceRiskService->getInstanceRisks( + $this->anr, + null, + ['limit' => -1, 'order' => 'maxRisk', 'order_direction' => 'desc', 'kindOfMeasure' => $i] + ); + $risksOpByTreatment = $this->anrInstanceRiskOpService->getOperationalRisks( + $this->anr, + null, + ['limit' => -1, 'order' => 'cacheNetRisk', 'order_direction' => 'desc', 'kindOfMeasure' => $i] + ); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $title = false; @@ -2485,220 +1846,112 @@ protected function generateRisksByKindOfTreatment() $title = true; $tableTitle = $section->addTable($this->noBorderTable); $tableTitle->addRow(400); - $tableTitle->addCell(Converter::cmToTwip(10.00)) - ->addText( - $this->getKindfofMeasureLabel($i), + $tableTitle->addCell(PhpWord\Shared\Converter::cmToTwip(10.00))->addText( + InstanceRiskSuperClass::getTreatmentNameByType($i), $this->titleFont, $this->leftParagraph ); $tableRiskInfo = $section->addTable($this->borderTable); $tableRiskInfo->addRow(400); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(5.50), $this->setColSpanCell(2, 'DFDFDF')) - ->addText( - $this->anrTranslate('Threat'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(10.00), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Vulnerability'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->boldFont, - $this->centerParagraph - ); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(5.50), $this->setColSpanCell(2, 'DFDFDF')) + ->addText($this->anrTranslate('Threat'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Vulnerability'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Residual risk'), $this->boldFont, $this->centerParagraph); $tableRiskInfo->addRow(400); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - 'C', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - 'I', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - $this->anrTranslate('A'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.50), $this->grayCell) - ->addText( - $this->anrTranslate('Label'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Label'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Existing controls'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Qualif.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - 'C', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - 'I', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - $this->anrTranslate('A'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText('C', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText('I', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText($this->anrTranslate('A'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.50), $this->grayCell) + ->addText($this->anrTranslate('Label'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Label'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Existing controls'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Qualif.'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText('C', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText('I', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText($this->anrTranslate('A'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); $impacts = ['c', 'i', 'd']; foreach ($risksByTreatment as $r) { foreach ($impacts as $impact) { - if ($r[$impact . '_risk_enabled'] == 0) { + if ($r[$impact . '_risk_enabled'] === 0) { $r[$impact . '_risk'] = null; } } foreach ($r as $key => $value) { - if ($value == -1) { + if ($value === -1) { $r[$key] = '-'; } } - $instance = $this->instanceTable->findById($r['instance']); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($r['instance'], $this->anr); if (!$instance->getObject()->isScopeGlobal()) { $path = $instance->getHierarchyString(); } else { - $path = $instance->{'getName' . $this->currentLangAnrIndex}() + $path = $instance->getName($this->currentLangAnrIndex) . ' (' . $this->anrTranslate('Global') . ')'; } $tableRiskInfo->addRow(400); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($path), - $this->normalFont, - $this->leftParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['c_impact'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['i_impact'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['d_impact'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.50), $this->vAlignCenterCell) + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($path), $this->normalFont, $this->leftParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['c_impact'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['i_impact'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($r['d_impact'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.50), $this->vAlignCenterCell) ->addText( _WT($r['threatLabel' . $this->currentLangAnrIndex]), $this->normalFont, $this->leftParagraph ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $r['threatRate'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($r['threatRate'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) ->addText( _WT($r['vulnLabel' . $this->currentLangAnrIndex]), $this->normalFont, $this->leftParagraph ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($r['comment']), - $this->normalFont, - $this->leftParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $r['vulnerabilityRate'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['c_risk'])) - ->addText( - $r['c_risk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['i_risk'])) - ->addText( - $r['i_risk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['d_risk'])) - ->addText( - $r['d_risk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->setBgColorCell($r['target_risk'])) - ->addText( - $r['target_risk'], - $this->boldFont, - $this->centerParagraph - ); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($r['comment']), $this->normalFont, $this->leftParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($r['vulnerabilityRate'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo + ->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->setBgColorCell($r['c_risk'])) + ->addText($r['c_risk'], $this->boldFont, $this->centerParagraph); + $tableRiskInfo + ->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->setBgColorCell($r['i_risk'])) + ->addText($r['i_risk'], $this->boldFont, $this->centerParagraph); + $tableRiskInfo + ->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->setBgColorCell($r['d_risk'])) + ->addText($r['d_risk'], $this->boldFont, $this->centerParagraph); + $tableRiskInfo + ->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->setBgColorCell($r['target_risk'])) + ->addText($r['target_risk'], $this->boldFont, $this->centerParagraph); } $section->addTextBreak(); } @@ -2706,154 +1959,86 @@ protected function generateRisksByKindOfTreatment() if (!$title) { $tableTitle = $section->addTable($this->noBorderTable); $tableTitle->addRow(400); - $tableTitle->addCell(Converter::cmToTwip(10.00), $this->setColSpanCell(13)) - ->addText( - $this->getKindfofMeasureLabel($i), - $this->titleFont, - $this->leftParagraph - ); + $tableTitle->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->setColSpanCell(13))->addText( + InstanceRiskOpSuperClass::getTreatmentNameByType($i), + $this->titleFont, + $this->leftParagraph + ); } $tableRiskOp = $section->addTable($this->borderTable); $tableRiskOp->addRow(400); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Risk description'), - $this->boldFont, - $this->centerParagraph - ); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp - ->addCell( - Converter::cmToTwip(5.50), - $this->setColSpanCell(2 + count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Inherent risk'), - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Risk description'), $this->boldFont, $this->centerParagraph); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(5.50), + $this->setColSpanCell(2 + count($opRisksImpactsScales), 'DFDFDF') + )->addText($this->anrTranslate('Inherent risk'), $this->boldFont, $this->centerParagraph); } - $tableRiskOp - ->addCell( - Converter::cmToTwip(15.00), - $this->setColSpanCell(3 + count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Net risk'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(15.00), + $this->setColSpanCell(3 + count($opRisksImpactsScales), 'DFDFDF') + )->addText($this->anrTranslate('Net risk'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Residual risk'), $this->boldFont, $this->centerParagraph); $tableRiskOp->addRow(400, $this->tblHeader); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->continueAndGrayCell); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp - ->addCell( - Converter::cmToTwip($sizeCellImpact), - $this->setColSpanCell(count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp - ->addCell( - Converter::cmToTwip($sizeCellImpact), + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->continueAndGrayCell); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip($sizeCellImpact), $this->setColSpanCell(count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(8.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Existing controls'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); - - $tableRiskOp->addRow(Converter::cmToTwip(1.00)); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->continueAndGrayCell); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); + )->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + } + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip($sizeCellImpact), + $this->setColSpanCell(count($opRisksImpactsScales), 'DFDFDF') + )->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Existing controls'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); + + $tableRiskOp->addRow(PhpWord\Shared\Converter::cmToTwip(1.00)); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->continueAndGrayCell); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); foreach ($opRisksImpactsScales as $opRiskImpactScale) { $label = mb_substr(_WT($opRiskImpactScale['label']), 0, 3) . '.'; - $tableRiskOp - ->addCell( - Converter::cmToTwip(0.70), - array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) - ) - ->addText( - $label, - $this->boldFont, - $this->verticalCenterParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(0.70), + array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) + )->addText($label, $this->boldFont, $this->verticalCenterParagraph); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); foreach ($opRisksImpactsScales as $opRiskImpactScale) { $label = mb_substr(_WT($opRiskImpactScale['label']), 0, 3) . '.'; - $tableRiskOp - ->addCell( - Converter::cmToTwip(0.70), - array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) - ) - ->addText( - $label, - $this->boldFont, - $this->verticalCenterParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(0.70), + array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) + )->addText($label, $this->boldFont, $this->verticalCenterParagraph); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(8.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); foreach ($risksOpByTreatment as $r) { - $instanceRiskOp = $this->get('instanceRiskOpTable')->findById($r['id']); + /** @var Entity\InstanceRiskOp $instanceRiskOp */ + $instanceRiskOp = $this->instanceRiskOpTable->findByIdAndAnr((int)$r['id'], $this->anr); foreach ($instanceRiskOp->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { $operationalRiskScaleType = $operationalInstanceRiskScale->getOperationalRiskScaleType(); $scalesData[$operationalRiskScaleType->getId()] = [ @@ -2867,87 +2052,61 @@ protected function generateRisksByKindOfTreatment() $r['scales'] = $scalesData; foreach ($r as $key => $value) { - if ($value == -1) { + if ($value === -1) { $r[$key] = '-'; } } - - $instance = $this->instanceTable->findById($r['instanceInfos']['id']); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($r['instanceInfos']['id'], $this->anr); $path = $instance->getHierarchyString(); $tableRiskOp->addRow(400); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($path), - $this->normalFont, - $this->leftParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($path), $this->normalFont, $this->leftParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) ->addText( _WT($r['label' . $this->currentLangAnrIndex]), $this->normalFont, $this->leftParagraph ); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $r['brutProb'], - $this->normalFont, - $this->centerParagraph - ); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($r['brutProb'], $this->normalFont, $this->centerParagraph); foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $tableRiskOp->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) ->addText( $r['scales'][$opRiskImpactScale['id']]['brutValue'], $this->normalFont, $this->centerParagraph ); } - $tableRiskOp - ->addCell( - Converter::cmToTwip(1.00), - $this->setBgColorCell($r['cacheBrutRisk'], false) - ) - ->addText( - $r['cacheBrutRisk'], - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($r['cacheBrutRisk'], false) + )->addText($r['cacheBrutRisk'], $this->boldFont, $this->centerParagraph); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $r['netProb'], - $this->normalFont, - $this->centerParagraph - ); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($r['netProb'], $this->normalFont, $this->centerParagraph); foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $tableRiskOp->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) ->addText( $r['scales'][$opRiskImpactScale['id']]['netValue'], $this->normalFont, $this->centerParagraph ); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['cacheNetRisk'], false)) - ->addText( - $r['cacheNetRisk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(8.00), $this->vAlignCenterCell) - ->addText( - _WT($r['comment']), - $this->normalFont, - $this->leftParagraph - ); - $cacheTargetedRisk = $r['cacheTargetedRisk'] == '-' ? $r['cacheNetRisk'] : $r['cacheTargetedRisk']; - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->setBgColorCell($cacheTargetedRisk, false)) - ->addText( - $cacheTargetedRisk, - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($r['cacheNetRisk'], false) + )->addText($r['cacheNetRisk'], $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->vAlignCenterCell) + ->addText(_WT($r['comment']), $this->normalFont, $this->leftParagraph); + $cacheTargetedRisk = $r['cacheTargetedRisk'] === '-' ? $r['cacheNetRisk'] : $r['cacheTargetedRisk']; + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(2.00), + $this->setBgColorCell($cacheTargetedRisk, false) + )->addText($cacheTargetedRisk, $this->boldFont, $this->centerParagraph); } $section->addTextBreak(); } @@ -2961,166 +2120,118 @@ protected function generateRisksByKindOfTreatment() * Generates the Risks Plan data * @return mixed|string The WordXml data generated */ - protected function generateRisksPlan() + private function generateRisksPlan() { - $recommendationRisks = $this->recommendationRiskTable->findByAnr($this->anr, ['r.position' => 'ASC']); + $recommendationRisks = $this->recommendationRiskTable->findByAnrOrderByAndCanExcludeNotTreated( + $this->anr, + ['r.position' => 'ASC'] + ); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); if (!empty($recommendationRisks)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(3.50), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Threat'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Vulnerability'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Existing controls'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Treatment'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.50), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Threat'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Vulnerability'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Existing controls'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Treatment'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Residual risk'), $this->boldFont, $this->centerParagraph); $table->addRow(); - $table->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $table->addCell(Converter::cmToTwip(6.00), $this->continueAndGrayCell); - $table->addCell(Converter::cmToTwip(6.00), $this->continueAndGrayCell); - $table->addCell(Converter::cmToTwip(6.00), $this->continueAndGrayCell); - $table->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - 'C', - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - 'I', - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - $this->anrTranslate('A'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->continueAndGrayCell); - $table->addCell(Converter::cmToTwip(2.10), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText('C', $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText('I', $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText($this->anrTranslate('A'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->continueAndGrayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->continueAndGrayCell); } - $previousRecoId = null; - $impacts = ['c', 'i', 'd']; - - //unset $global = []; $toUnset = []; foreach ($recommendationRisks as $recommendationRisk) { - if ($recommendationRisk->hasGlobalObjectRelation()) { - $key = $recommendationRisk->getRecommandation()->getUuid() - . ' - ' . $recommendationRisk->getThreat()->getUuid() - . ' - ' . $recommendationRisk->getVulnerability()->getUuid() - . ' - ' . $recommendationRisk->getGlobalObject()->getUuid(); - if (\array_key_exists($key, $global)) { - if (\array_key_exists($key, $toUnset) - && $recommendationRisk->getInstanceRisk()->getCacheMaxRisk() > $toUnset[$key] - ) { - $toUnset[$key] = $recommendationRisk->getInstanceRisk()->getCacheMaxRisk(); + $instanceRisk = $recommendationRisk->getInstanceRisk(); + if ($instanceRisk !== null && $recommendationRisk->hasGlobalObjectRelation()) { + $key = $recommendationRisk->getRecommendation()->getUuid() + . ' - ' . $recommendationRisk->getThreat()?->getUuid() + . ' - ' . $recommendationRisk->getVulnerability()?->getUuid() + . ' - ' . $recommendationRisk->getGlobalObject()?->getUuid(); + if (array_key_exists($key, $global)) { + if (array_key_exists($key, $toUnset) && $instanceRisk->getCacheMaxRisk() > $toUnset[$key]) { + $toUnset[$key] = $instanceRisk->getCacheMaxRisk(); } else { - $toUnset[$key] = max($recommendationRisk->getInstanceRisk()->getCacheMaxRisk(), $global[$key]); + $toUnset[$key] = max($instanceRisk->getCacheMaxRisk(), $global[$key]); } } - $global[$key] = $recommendationRisk->getInstanceRisk()->getCacheMaxRisk(); + $global[$key] = $instanceRisk->getCacheMaxRisk(); } } + + $previousRecoId = null; $alreadySet = []; foreach ($recommendationRisks as $recommendationRisk) { - if ($recommendationRisk->getInstanceRisk()) { - foreach ($impacts as $impact) { - $risk = 'risk' . ucfirst($impact); - if ($impact == 'd') { - $impact = 'a'; // Changed to get threat->a value; - } - ${'risk' . ucfirst($impact)} = $recommendationRisk->getInstanceRisk()->$risk; - - if ($recommendationRisk->getInstanceRisk()->$risk == -1) { - ${'risk' . ucfirst($impact)} = '-'; - } - - if (!$recommendationRisk->getThreat()->$impact) { - ${'risk' . ucfirst($impact)} = null; - } + $instanceRisk = $recommendationRisk->getInstanceRisk(); + if ($instanceRisk !== null && $recommendationRisk->getThreat() !== null) { + $riskConfidentiality = null; + $riskAvailability = null; + $riskIntegrity = null; + if ($recommendationRisk->getThreat()->getConfidentiality()) { + $riskConfidentiality = $instanceRisk->getRiskConfidentiality() === -1 + ? '-' + : $instanceRisk->getRiskConfidentiality(); } - - $importance = ''; - for ($i = 0; $i <= ($recommendationRisk->getRecommandation()->getImportance() - 1); $i++) { - $importance .= '●'; + if ($recommendationRisk->getThreat()->getIntegrity()) { + $riskIntegrity = $instanceRisk->getRiskIntegrity() === -1 ? '-' : $instanceRisk->getRiskIntegrity(); + } + if ($recommendationRisk->getThreat()->getAvailability()) { + $riskAvailability = $instanceRisk->getRiskAvailability() === -1 + ? '-' + : $instanceRisk->getRiskAvailability(); } - if ($recommendationRisk->getRecommandation()->getUuid() !== $previousRecoId) { + $importance = str_repeat('●', $recommendationRisk->getRecommendation()->getImportance()); + + if ($recommendationRisk->getRecommendation()->getUuid() !== $previousRecoId) { $table->addRow(400); - $cellReco = $table->addCell(Converter::cmToTwip(5.00), $this->setColSpanCell(9, 'DBE5F1')); - $cellRecoRun = $cellReco->addTextRun($this->leftParagraph); - $cellRecoRun->addText( - $importance . ' ', - $this->redFont - ); - $cellRecoRun->addText( - _WT($recommendationRisk->getRecommandation()->getCode()), - $this->boldFont + $cellReco = $table->addCell( + PhpWord\Shared\Converter::cmToTwip(5.00), + $this->setColSpanCell(9, 'DBE5F1') ); + $cellRecoRun = $cellReco->addTextRun($this->leftParagraph); + $cellRecoRun->addText($importance . ' ', $this->redFont); + $cellRecoRun->addText(_WT($recommendationRisk->getRecommendation()->getCode()), $this->boldFont); $cellRecoRun->addText( - ' - ' . _WT($recommendationRisk->getRecommandation()->getDescription()), + ' - ' . _WT($recommendationRisk->getRecommendation()->getDescription()), $this->boldFont ); } $continue = true; - $key = $recommendationRisk->getRecommandation()->getUuid() + $key = $recommendationRisk->getRecommendation()->getUuid() . ' - ' . $recommendationRisk->getThreat()->getUuid() - . ' - ' . $recommendationRisk->getVulnerability()->getUuid() - . ' - ' . ( - $recommendationRisk->hasGlobalObjectRelation() - ? $recommendationRisk->getGlobalObject()->getUuid() - : '' - ); + . ' - ' . $recommendationRisk->getVulnerability()?->getUuid() + . ' - ' . $recommendationRisk->getGlobalObject()?->getUuid(); if (isset($toUnset[$key])) { - if ($recommendationRisk->getInstanceRisk()->getCacheMaxRisk() < $toUnset[$key] - || isset($alreadySet[$key]) + if (isset($alreadySet[$key]) + || $instanceRisk->getCacheMaxRisk() < $toUnset[$key] ) { $continue = false; } else { @@ -3132,67 +2243,43 @@ protected function generateRisksPlan() $path = $this->getObjectInstancePath($recommendationRisk); $table->addRow(400); - $table->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($path), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) - ->addText( - _WT($recommendationRisk->getThreat()->{'label' . $this->currentLangAnrIndex}), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($path), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recommendationRisk->getVulnerability()->{'label' . $this->currentLangAnrIndex}), + _WT($recommendationRisk->getThreat()->getLabel($this->currentLangAnrIndex)), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recommendationRisk->getInstanceRisk()->getComment()), + _WT($recommendationRisk->getVulnerability()?->getLabel($this->currentLangAnrIndex)), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(0.70), $this->setBgColorCell($riskC)) - ->addText( - $riskC, - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->setBgColorCell($riskI)) - ->addText( - $riskI, - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(0.70), $this->setBgColorCell($riskA)) - ->addText( - $riskA, - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) + ->addText(_WT($instanceRisk->getComment()), $this->normalFont, $this->leftParagraph); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(0.70), + $this->setBgColorCell($riskConfidentiality) + )->addText((string)$riskConfidentiality, $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->setBgColorCell($riskIntegrity)) + ->addText((string)$riskIntegrity, $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->setBgColorCell($riskAvailability)) + ->addText((string)$riskAvailability, $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->vAlignCenterCell) ->addText( - $this->anrTranslate($recommendationRisk->getInstanceRisk()->getTreatmentName()), + $this->anrTranslate($instanceRisk->getTreatmentName()), $this->normalFont, $this->leftParagraph ); - $table - ->addCell( - Converter::cmToTwip(2.10), - $this->setBgColorCell($recommendationRisk->getInstanceRisk()->getCacheTargetedRisk()) - ) - ->addText( - $recommendationRisk->getInstanceRisk()->getCacheTargetedRisk(), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(2.10), + $this->setBgColorCell($instanceRisk->getCacheTargetedRisk()) + )->addText((string)$instanceRisk->getCacheTargetedRisk(), $this->boldFont, $this->centerParagraph); } } - $previousRecoId = $recommendationRisk->getRecommandation()->getUuid(); + $previousRecoId = $recommendationRisk->getRecommendation()->getUuid(); } return $table; @@ -3202,83 +2289,59 @@ protected function generateRisksPlan() * Generates the Operational Risks Plan data * @return mixed|string The WordXml data generated */ - protected function generateOperationalRisksPlan() + private function generateOperationalRisksPlan() { - $recommendationRisks = $this->recommendationRiskTable->findByAnr($this->anr, ['r.position' => 'ASC']); + $recommendationRisks = $this->recommendationRiskTable->findByAnrOrderByAndCanExcludeNotTreated( + $this->anr, + ['r.position' => 'ASC'] + ); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); if (!empty($recommendationRisks)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(3.00), $this->grayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(12.20), $this->grayCell) - ->addText( - $this->anrTranslate('Risk description'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Existing controls'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->grayCell) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->grayCell) - ->addText( - $this->anrTranslate('Treatment'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->grayCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->grayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(12.20), $this->grayCell) + ->addText($this->anrTranslate('Risk description'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Existing controls'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->grayCell) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->grayCell) + ->addText($this->anrTranslate('Treatment'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->grayCell) + ->addText($this->anrTranslate('Residual risk'), $this->boldFont, $this->centerParagraph); } $previousRecoId = null; foreach ($recommendationRisks as $recommendationRisk) { if ($recommendationRisk->getInstanceRiskOp()) { - $cacheNetRisk = $recommendationRisk->getInstanceRiskOp()->getCacheNetRisk() !== -1 ? - $recommendationRisk->getInstanceRiskOp()->getCacheNetRisk() : - '-'; - $cacheTargetedRisk = $recommendationRisk->getInstanceRiskOp()->getCacheTargetedRisk() !== -1 ? - $recommendationRisk->getInstanceRiskOp()->getCacheTargetedRisk() : - $cacheNetRisk; + $cacheNetRisk = $recommendationRisk->getInstanceRiskOp()->getCacheNetRisk() !== -1 + ? $recommendationRisk->getInstanceRiskOp()->getCacheNetRisk() + : '-'; + $cacheTargetedRisk = $recommendationRisk->getInstanceRiskOp()->getCacheTargetedRisk() !== -1 + ? $recommendationRisk->getInstanceRiskOp()->getCacheTargetedRisk() + : $cacheNetRisk; $importance = ''; - for ($i = 0; $i <= ($recommendationRisk->getRecommandation()->getImportance() - 1); $i++) { + for ($i = 0; $i <= ($recommendationRisk->getRecommendation()->getImportance() - 1); $i++) { $importance .= '●'; } - if ($recommendationRisk->getRecommandation()->getUuid() !== $previousRecoId) { + if ($recommendationRisk->getRecommendation()->getUuid() !== $previousRecoId) { $table->addRow(400); - $cellReco = $table->addCell(Converter::cmToTwip(5.00), $this->setColSpanCell(6, 'DBE5F1')); - $cellRecoRun = $cellReco->addTextRun($this->leftParagraph); - $cellRecoRun->addText( - $importance . ' ', - $this->redFont - ); - $cellRecoRun->addText( - _WT($recommendationRisk->getRecommandation()->getCode()), - $this->boldFont + $cellReco = $table->addCell( + PhpWord\Shared\Converter::cmToTwip(5.00), + $this->setColSpanCell(6, 'DBE5F1') ); + $cellRecoRun = $cellReco->addTextRun($this->leftParagraph); + $cellRecoRun->addText($importance . ' ', $this->redFont); + $cellRecoRun->addText(_WT($recommendationRisk->getRecommendation()->getCode()), $this->boldFont); $cellRecoRun->addText( - ' - ' . _WT($recommendationRisk->getRecommandation()->getDescription()), + ' - ' . _WT($recommendationRisk->getRecommendation()->getDescription()), $this->boldFont ); } @@ -3286,45 +2349,35 @@ protected function generateOperationalRisksPlan() $path = $this->getObjectInstancePath($recommendationRisk); $table->addRow(400); - $table->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($path), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(12.20), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($path), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(12.20), $this->vAlignCenterCell) ->addText( - _WT($recommendationRisk->getInstanceRiskOp()->{'riskCacheLabel' . $this->currentLangAnrIndex}), + _WT($recommendationRisk->getInstanceRiskOp()->getRiskCacheLabel($this->currentLangAnrIndex)), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( _WT($recommendationRisk->getInstanceRiskOp()->getComment()), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(2.10), $this->setBgColorCell($cacheNetRisk, false)) - ->addText( - $cacheNetRisk, - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.10), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->setBgColorCell($cacheNetRisk, false)) + ->addText($cacheNetRisk, $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.10), $this->vAlignCenterCell) ->addText( $this->anrTranslate($recommendationRisk->getInstanceRiskOp()->getTreatmentName()), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(2.10), $this->setBgColorCell($cacheTargetedRisk, false)) - ->addText( - $cacheTargetedRisk, - $this->boldFont, - $this->centerParagraph - ); + $table->addCell( + PhpWord\Shared\Converter::cmToTwip(2.10), + $this->setBgColorCell($cacheTargetedRisk, false) + )->addText($cacheTargetedRisk, $this->boldFont, $this->centerParagraph); - $previousRecoId = $recommendationRisk->getRecommandation()->getUuid(); + $previousRecoId = $recommendationRisk->getRecommendation()->getUuid(); } } @@ -3335,95 +2388,68 @@ protected function generateOperationalRisksPlan() * Generates the Implamentation Recommendations Plan data * @return mixed|string The WordXml data generated */ - protected function generateTableImplementationPlan() + private function generateTableImplementationPlan() { - $recommendationRisks = $this->recommendationRiskTable->findByAnr($this->anr, ['r.position' => 'ASC']); + $recommendationRisks = $this->recommendationRiskTable->findByAnrOrderByAndCanExcludeNotTreated( + $this->anr, + ['r.position' => 'ASC'] + ); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); if (!empty($recommendationRisks)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(10.00), $this->grayCell) - ->addText( - $this->anrTranslate('Recommendation'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Imp.'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->grayCell) - ->addText( - $this->anrTranslate('Comment'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Manager'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(3.00), $this->grayCell) - ->addText( - $this->anrTranslate('Deadline'), - $this->boldFont, - $this->centerParagraph - ); - } - + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->grayCell) + ->addText($this->anrTranslate('Recommendation'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Imp.'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->grayCell) + ->addText($this->anrTranslate('Comment'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Manager'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->grayCell) + ->addText($this->anrTranslate('Deadline'), $this->boldFont, $this->centerParagraph); + } + + $globalObjectsRecommendationsKeys = []; foreach ($recommendationRisks as $recommendationRisk) { - $recommendation = $recommendationRisk->getRecommandation(); + $recommendation = $recommendationRisk->getRecommendation(); + if ($recommendationRisk->hasGlobalObjectRelation()) { + $key = 'o' . $recommendationRisk->getGlobalObject()->getUuid() + . '-' . $recommendationRisk->getInstanceRisk()->getThreat()->getUuid() + . '-' . $recommendationRisk->getInstanceRisk()->getVulnerability()->getUuid() + . '-' . $recommendation->getUuid(); + if (isset($globalObjectsRecommendationsKeys[$key])) { + continue; + } + $globalObjectsRecommendationsKeys[$key] = $key; + } + $importance = ''; for ($i = 0; $i <= ($recommendation->getImportance() - 1); $i++) { $importance .= '●'; } $recoDeadline = ''; - if ($recommendation->getDueDate()) { + if ($recommendation->getDueDate() !== null) { $recoDeadline = $recommendation->getDueDate()->format('d-m-Y'); } $table->addRow(400); - $cellRecoName = $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell); + $cellRecoName = $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell); $cellRecoNameRun = $cellRecoName->addTextRun($this->leftParagraph); - $cellRecoNameRun->addText( - _WT($recommendation->getCode()) . '', - $this->boldFont - ); - $cellRecoNameRun->addText( - _WT($recommendation->getDescription()), - $this->normalFont - ); - $table->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $importance, - $this->redFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($recommendation->getComment()), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($recommendation->getResponsable()), - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - $recoDeadline, - $this->normalFont, - $this->centerParagraph - ); + $cellRecoNameRun->addText(_WT($recommendation->getCode()) . '', $this->boldFont); + $cellRecoNameRun->addText(_WT($recommendation->getDescription()), $this->normalFont); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($importance, $this->redFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($recommendation->getComment()), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($recommendation->getResponsible()), $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText($recoDeadline, $this->normalFont, $this->centerParagraph); } return $table; @@ -3433,1034 +2459,618 @@ protected function generateTableImplementationPlan() * Generates the Implamentation Recommendations Plan data * @return mixed|string The WordXml data generated */ - protected function generateTableImplementationHistory() + private function generateTableImplementationHistory() { - $recoRecords = $this->recommendationHistoricTable->findByAnr($this->anr); + /** @var Entity\RecommendationHistory[] $recoRecords */ + $recoRecords = $this->recommendationHistoryTable->findByAnr($this->anr); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); if ($recoRecords) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(3.00), $this->grayCell) - ->addText( - $this->anrTranslate('By'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Recommendation'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(8.00), $this->grayCell) - ->addText( - $this->anrTranslate('Risk'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->grayCell) - ->addText( - $this->anrTranslate('Implementation comment'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.75), $this->grayCell) - ->addText( - $this->anrTranslate('Risk before'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.75), $this->grayCell) - ->addText( - $this->anrTranslate('Risk after'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->grayCell) + ->addText($this->anrTranslate('By'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Recommendation'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->grayCell) + ->addText($this->anrTranslate('Risk'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->grayCell) + ->addText($this->anrTranslate('Implementation comment'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.75), $this->grayCell) + ->addText($this->anrTranslate('Risk before'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.75), $this->grayCell) + ->addText($this->anrTranslate('Risk after'), $this->boldFont, $this->centerParagraph); } - $previousRecoId = null; - foreach ($recoRecords as $recoRecord) { $importance = ''; - for ($i = 0; $i <= ($recoRecord->recoImportance - 1); $i++) { + for ($i = 0; $i <= ($recoRecord->getRecoImportance() - 1); $i++) { $importance .= '●'; } - if ($recoRecord->recoDuedate == null) { - $recoDeadline = ''; - } else { - $recoDeadline = $recoRecord->recoDuedate->format('d/m/Y'); - } + $recoDeadline = $recoRecord->getRecoDueDate() === null + ? '' + : $recoRecord->getRecoDueDate()->format('d/m/Y'); - $recoValidationDate = $recoRecord->createdAt->format('d/m/Y'); + $recoValidationDate = $recoRecord->getCreatedAt()->format('d/m/Y'); - if ($recoRecord->riskColorBefore == "green") { + $riskMaxBefore = $recoRecord->getRiskMaxRiskBefore(); + $bgcolorRiskBefore = 'FD661F'; + if ($recoRecord->getRiskColorBefore() === 'green') { $bgcolorRiskBefore = 'D6F107'; - } else { - if ($recoRecord->riskColorBefore == "orange") { - $bgcolorRiskBefore = 'FFBC1C'; - } else { - if ($recoRecord->riskMaxRiskBefore == -1) { - $recoRecord->riskMaxRiskBefore = '-'; - $bgcolorRiskBefore = 'FFFFFF'; - } else { - $bgcolorRiskBefore = 'FD661F'; - } - } + } elseif ($recoRecord->getRiskColorBefore() === 'orange') { + $bgcolorRiskBefore = 'FFBC1C'; + } elseif ($riskMaxBefore === -1) { + $riskMaxBefore = '-'; + $bgcolorRiskBefore = 'FFFFFF'; } - $styleContentCellRiskBefore = ['valign' => 'center', 'bgcolor' => $bgcolorRiskBefore]; - if ($recoRecord->riskColorAfter == "green") { + $riskMaxAfter = $recoRecord->getRiskMaxRiskAfter(); + $bgcolorRiskAfter = 'FD661F'; + if ($recoRecord->getRiskColorAfter() === 'green') { $bgcolorRiskAfter = 'D6F107'; - } else { - if ($recoRecord->riskColorAfter == "orange") { - $bgcolorRiskAfter = 'FFBC1C'; - } else { - if ($recoRecord->riskMaxRiskAfter == -1) { - $recoRecord->riskMaxRiskAfter = '-'; - $bgcolorRiskAfter = 'FFFFFF'; - } else { - $bgcolorRiskBefore = 'FD661F'; - } - } + } elseif ($recoRecord->getRiskColorAfter() === 'orange') { + $bgcolorRiskAfter = 'FFBC1C'; + } elseif ($riskMaxAfter === -1) { + $riskMaxAfter = '-'; + $bgcolorRiskAfter = 'FFFFFF'; } - $styleContentCellRiskAfter = ['valign' => 'center', 'bgcolor' => $bgcolorRiskAfter]; $table->addRow(400); - $table->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($recoRecord->creator), - $this->normalFont, - $this->leftParagraph - ); - $cellReco = $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($recoRecord->getCreator()), $this->normalFont, $this->leftParagraph); + $cellReco = $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell); $cellRecoRun = $cellReco->addTextRun($this->leftParagraph); - $cellRecoRun->addText( - $importance . ' ', - $this->redFont - ); - $cellRecoRun->addText( - _WT($recoRecord->recoCode) . '', - $this->boldFont - ); - $cellRecoRun->addText( - _WT($recoRecord->recoDescription) . '' . '', - $this->normalFont - ); - $cellRecoRun->addText( - $this->anrTranslate('Comment') . ': ', - $this->boldFont - ); - $cellRecoRun->addText( - _WT($recoRecord->recoComment) . '', - $this->normalFont - ); - $cellRecoRun->addText( - $this->anrTranslate('Deadline') . ': ', - $this->boldFont - ); - $cellRecoRun->addText( - $recoDeadline . '', - $this->normalFont - ); - $cellRecoRun->addText( - $this->anrTranslate('Validation date') . ': ', - $this->boldFont - ); - $cellRecoRun->addText( - $recoValidationDate . '', - $this->normalFont - ); - $cellRecoRun->addText( - $this->anrTranslate('Manager') . ': ', - $this->boldFont - ); - $cellRecoRun->addText( - _WT($recoRecord->recoResponsable), - $this->normalFont - ); - $cellRisk = $table->addCell(Converter::cmToTwip(8.00), $this->vAlignCenterCell); + $cellRecoRun->addText($importance . ' ', $this->redFont); + $cellRecoRun->addText(_WT($recoRecord->getRecoCode()) . '', $this->boldFont); + $cellRecoRun->addText(_WT($recoRecord->getRecoDescription()) . '' . '', $this->normalFont); + $cellRecoRun->addText($this->anrTranslate('Comment') . ': ', $this->boldFont); + $cellRecoRun->addText(_WT($recoRecord->getRecoComment()) . '', $this->normalFont); + $cellRecoRun->addText($this->anrTranslate('Deadline') . ': ', $this->boldFont); + $cellRecoRun->addText($recoDeadline . '', $this->normalFont); + $cellRecoRun->addText($this->anrTranslate('Validation date') . ': ', $this->boldFont); + $cellRecoRun->addText($recoValidationDate . '', $this->normalFont); + $cellRecoRun->addText($this->anrTranslate('Manager') . ': ', $this->boldFont); + $cellRecoRun->addText(_WT($recoRecord->getRecoResponsable()), $this->normalFont); + $cellRisk = $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->vAlignCenterCell); $cellRiskRun = $cellRisk->addTextRun($this->leftParagraph); + $cellRiskRun->addText($this->anrTranslate('Asset type') . ': ', $this->boldFont); + $cellRiskRun->addText(_WT($recoRecord->getRiskAsset()) . '', $this->normalFont); + $cellRiskRun->addText($this->anrTranslate('Asset') . ': ', $this->boldFont); + $cellRiskRun->addText(_WT($recoRecord->getRiskInstance()) . '', $this->normalFont); + $cellRiskRun->addText($this->anrTranslate('Threat') . ': ', $this->boldFont); + $cellRiskRun->addText(_WT($recoRecord->getRiskThreat()) . '', $this->normalFont); + $cellRiskRun->addText($this->anrTranslate('Vulnerability') . ': ', $this->boldFont); + $cellRiskRun->addText(_WT($recoRecord->getRiskVul()) . '', $this->normalFont); + $cellRiskRun->addText($this->anrTranslate('Treatment type') . ': ', $this->boldFont); $cellRiskRun->addText( - $this->anrTranslate('Asset type') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - _WT($recoRecord->riskAsset) . '', - $this->normalFont - ); - $cellRiskRun->addText( - $this->anrTranslate('Asset') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - _WT($recoRecord->riskInstance) . '', - $this->normalFont - ); - $cellRiskRun->addText( - $this->anrTranslate('Threat') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - _WT($recoRecord->riskThreat) . '', - $this->normalFont - ); - $cellRiskRun->addText( - $this->anrTranslate('Vulnerability') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - _WT($recoRecord->riskVul) . '', - $this->normalFont - ); - $cellRiskRun->addText( - $this->anrTranslate('Treatment type') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - $this->getKindfofMeasureLabel($recoRecord->riskKindOfMeasure) . '', - $this->normalFont - ); - $cellRiskRun->addText( - $this->anrTranslate('Existing controls') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - _WT($recoRecord->riskCommentBefore) . '', + InstanceRiskSuperClass::getTreatmentNameByType($recoRecord->getRiskKindOfMeasure()) . '', $this->normalFont ); - $cellRiskRun->addText( - $this->anrTranslate('New controls') . ': ', - $this->boldFont - ); - $cellRiskRun->addText( - _WT($recoRecord->riskCommentAfter) . '', - $this->normalFont - ); - $table->addCell(Converter::cmToTwip(4.50), $this->vAlignCenterCell) - ->addText( - _WT($recoRecord->implComment), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(1.75), $styleContentCellRiskBefore) - ->addText( - $recoRecord->riskMaxRiskBefore, - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.75), $styleContentCellRiskAfter) - ->addText( - $recoRecord->riskMaxRiskAfter, - $this->boldFont, - $this->centerParagraph - ); - - $previousRecoRecordId = $recoRecord->id; + $cellRiskRun->addText($this->anrTranslate('Existing controls') . ': ', $this->boldFont); + $cellRiskRun->addText(_WT($recoRecord->getRiskCommentBefore()) . '', $this->normalFont); + $cellRiskRun->addText($this->anrTranslate('New controls') . ': ', $this->boldFont); + $cellRiskRun->addText(_WT($recoRecord->getRiskCommentAfter()) . '', $this->normalFont); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->vAlignCenterCell) + ->addText(_WT($recoRecord->getImplComment()), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.75), $styleContentCellRiskBefore) + ->addText($riskMaxBefore, $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.75), $styleContentCellRiskAfter) + ->addText($riskMaxAfter, $this->boldFont, $this->centerParagraph); } return $table; } /** - * Generates the Statement Of Applicability Scale - * @return mixed|string The WordXml data generated + * Generates the Statement Of Applicability Scale. + * + * @param Entity\SoaScaleComment[] $soaScaleComments */ - protected function generateTableStatementOfApplicabilityScale($soaScaleComments, $translations) + private function generateTableStatementOfApplicabilityScale(array $soaScaleComments): PhpWord\Element\Table { - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); $noBorderCell = [ 'borderTopColor' => 'FFFFFF', 'borderTopSize' => 0, - 'borderLeftColor' => 'FFFFFF', + 'borderLeftColor' => 'FFFFFF', 'borderLeftSize' => 0, ]; if (!empty($soaScaleComments)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.00), $noBorderCell); - $table->addCell(Converter::cmToTwip(8.00), $this->grayCell) - ->addText( - $this->anrTranslate('Level of compliance'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $noBorderCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->grayCell) + ->addText($this->anrTranslate('Level of compliance'), $this->boldFont, $this->centerParagraph); foreach ($soaScaleComments as $comment) { $table->addRow(400); - $translationComment = $translations[$comment->getCommentTranslationKey()] ?? null; - - $table->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $comment->getScaleIndex(), - $this->normalFont, - $this->centerParagraph - ); - + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText((string)$comment->getScaleIndex(), $this->normalFont, $this->centerParagraph); $this->customizableCell['BgColor'] = $comment->getColour(); - - $table->addCell(Converter::cmToTwip(8.00), $this->customizableCell) - ->addText( - _WT($translationComment !== null ? $translationComment->getValue() : ''), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->customizableCell) + ->addText(_WT($comment->getComment()), $this->normalFont, $this->leftParagraph); } } + return $table; } /** * Generates the Statement Of Applicability data - * @return mixed|string The WordXml data generated */ - protected function generateTableStatementOfApplicability($referential, $translations) + private function generateTableStatementOfApplicability(string $referentialUuid): PhpWord\Element\Table { - /** @var SoaService $soaService */ - $soaService = $this->soaService; - $filterMeasures['r.anr'] = $this->anr->getId(); - $filterMeasures['r.uuid'] = $referential; - $measureService = $this->measureService; - $measuresFiltered = $measureService->getList(1, 0, null, null, $filterMeasures); - $measuresFilteredId = []; - foreach ($measuresFiltered as $key) { - array_push($measuresFilteredId, $key['uuid']); - } - $filterAnd['m.uuid'] = [ - 'op' => 'IN', - 'value' => $measuresFilteredId, - ]; - $filterAnd['m.anr'] = $this->anr->getId(); - $controlSoaList = $soaService->getList(1, 0, 'm.code', null, $filterAnd); + $measures = $this->measureTable->findByAnrAndReferentialUuidOrderByCode($this->anr, $referentialUuid); - //create section - $tableWord = new PhpWord(); + /* Create section. */ + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); - //header if array is not empty - if (count($controlSoaList)) { - $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - $this->anrTranslate('Code'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->grayCell) - ->addText( - $this->anrTranslate('Control'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Inclusion/Exclusion'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->grayCell) - ->addText( - $this->anrTranslate('Remarks/Justification'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->grayCell) - ->addText( - $this->anrTranslate('Evidences'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->grayCell) - ->addText( - $this->anrTranslate('Actions'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Level of compliance'), - $this->boldFont, - $this->centerParagraph - ); - } - - $inclusions = [ + $inclusionsTranslations = [ 'EX' => $this->anrTranslate('Excluded'), 'LR' => $this->anrTranslate('Legal requirements'), 'CO' => $this->anrTranslate('Contractual obligations'), 'BR' => $this->anrTranslate('Business requirements'), 'BP' => $this->anrTranslate('Best practices'), - 'RRA' => $this->anrTranslate('Results of risk assessment') + 'RRA' => $this->anrTranslate('Results of risk assessment'), ]; - $previousCatId = null; + $isTitleSet = false; + foreach ($measures as $measure) { + $soa = $measure->getSoa(); + if ($soa === null) { + continue; + } - foreach ($controlSoaList as $controlSoa) { - $getInclusions = []; - foreach ($inclusions as $incl => $value) { - if ($controlSoa[$incl]) { - $getInclusions[] = $value; - } + if (!$isTitleSet) { + $table->addRow(400, $this->tblHeader); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText($this->anrTranslate('Code'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->grayCell) + ->addText($this->anrTranslate('Control'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Inclusion/Exclusion'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->grayCell) + ->addText($this->anrTranslate('Remarks/Justification'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->grayCell) + ->addText($this->anrTranslate('Evidences'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->grayCell) + ->addText($this->anrTranslate('Actions'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Level of compliance'), $this->boldFont, $this->centerParagraph); + $isTitleSet = true; } - $inclusion = join("\n\n", $getInclusions); + + $inclusions = []; + if ($soa->getEx()) { + $inclusions[] = $inclusionsTranslations['EX']; + } + if ($soa->getLr()) { + $inclusions[] = $inclusionsTranslations['LR']; + } + if ($soa->getCo()) { + $inclusions[] = $inclusionsTranslations['CO']; + } + if ($soa->getBr()) { + $inclusions[] = $inclusionsTranslations['BR']; + } + if ($soa->getBp()) { + $inclusions[] = $inclusionsTranslations['BP']; + } + if ($soa->getRra()) { + $inclusions[] = $inclusionsTranslations['RRA']; + } + $inclusion = implode("\n\n", $inclusions); $complianceLevel = ""; $bgcolor = 'FFFFFF'; - if (!is_null($controlSoa['soaScaleComment']) && !$controlSoa['soaScaleComment']->isHidden()) { - $translationComment = $translations[ - $controlSoa['soaScaleComment']->getCommentTranslationKey() - ] ?? null; - $complianceLevel = $translationComment !== null ? $translationComment->getValue() : ''; - $bgcolor = $controlSoa['soaScaleComment']->getColour(); + $soaScaleComment = $soa->getSoaScaleComment(); + if ($soaScaleComment !== null && !$soaScaleComment->isHidden()) { + $complianceLevel = $soaScaleComment->getComment(); + $bgcolor = $soaScaleComment->getColour(); } - if ($controlSoa['EX']) { + if ($soa->getEx()) { $complianceLevel = ""; $bgcolor = 'E7E6E6'; } $styleContentCellCompliance = ['valign' => 'center', 'bgcolor' => $bgcolor]; - if ($controlSoa['measure']->category->id != $previousCatId) { + if ($measure->getCategory() !== null && $measure->getCategory()->getId() !== $previousCatId) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(10.00), $this->setColSpanCell(7, 'DBE5F1')) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->setColSpanCell(7, 'DBE5F1')) ->addText( - _WT($controlSoa['measure']->category->get('label' . $this->currentLangAnrIndex)), + _WT($measure->getCategory()->getLabel($this->currentLangAnrIndex)), $this->boldFont, $this->leftParagraph ); + $previousCatId = $measure->getCategory()->getId(); } - $previousCatId = $controlSoa['measure']->category->id; $table->addRow(400); - $table->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - _WT($controlSoa['measure']->code), - $this->normalFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($controlSoa['measure']->get('label' . $this->currentLangAnrIndex)), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($inclusion), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($controlSoa['remarks']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText(_WT($measure->getCode()), $this->normalFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) ->addText( - _WT($controlSoa['evidences']), + _WT($measure->getLabel($this->currentLangAnrIndex)), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(5.00), $this->vAlignCenterCell) - ->addText( - _WT($controlSoa['actions']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(2.00), $styleContentCellCompliance) - ->addText( - _WT($complianceLevel), - $this->normalFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($inclusion), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($soa->getRemarks()), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($soa->getEvidences()), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->vAlignCenterCell) + ->addText(_WT($soa->getActions()), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $styleContentCellCompliance) + ->addText(_WT($complianceLevel), $this->normalFont, $this->centerParagraph); } return $table; } /** - * Generates the table risks by control in SOA + * Generates the table risks by control in SOA. + * * @return mixed|string The WordXml data generated */ - protected function generateTableRisksByControl($referential) + private function generateTableRisksByControl(string $referentialUuid) { - /** @var SoaService $soaService */ - $soaService = $this->soaService; - $filterMeasures['r.anr'] = $this->anr->getId(); - $filterMeasures['r.uuid'] = $referential; - $measureService = $this->measureService; - $measuresFiltered = $measureService->getList(1, 0, null, null, $filterMeasures); - $measuresFilteredId = []; - foreach ($measuresFiltered as $key) { - array_push($measuresFilteredId, $key['uuid']); - } - $filterAnd['m.uuid'] = [ - 'op' => 'IN', - 'value' => $measuresFilteredId, - ]; - $filterAnd['m.anr'] = $this->anr->getId(); - $controlSoaList = $soaService->getList(1, 0, 'm.code', null, $filterAnd); - $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr->getId()); - $opRisksImpactsScaleType = array_values(array_filter($opRisksAllScales, function ($scale) { - return $scale['type'] == 1; - })); - $opRisksImpactsScales = array_filter($opRisksImpactsScaleType[0]['scaleTypes'], function ($scale) { - return $scale['isHidden'] == false; + $opRisksAllScales = $this->operationalRiskScaleService->getOperationalRiskScales($this->anr); + $opRisksImpactsScaleType = array_values( + array_filter($opRisksAllScales, static function ($scale) { + return $scale['type'] === OperationalRiskScaleSuperClass::TYPE_IMPACT; + }) + ); + $opRisksImpactsScales = array_filter($opRisksImpactsScaleType[0]['scaleTypes'], static function ($scale) { + return !$scale['isHidden']; }); $sizeCellImpact = count($opRisksImpactsScales) * 0.70; //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); - $previousControlId = null; + $measures = $this->measureTable->findByAnrAndReferentialUuidOrderByCode($this->anr, $referentialUuid); + $previousMeasureUuid = null; + foreach ($measures as $measure) { + $soa = $measure->getSoa(); + if ($soa === null) { + continue; + } - foreach ($controlSoaList as $controlSoa) { - $amvs = []; - $rolfRisks = []; - foreach ($controlSoa['measure']->amvs as $amv) { - $amvs[] = $amv->getUuid(); + $amvUuids = []; + $rolfRiskIds = []; + foreach ($measure->getAmvs() as $amv) { + $amvUuids[] = $amv->getUuid(); } - foreach ($controlSoa['measure']->rolfRisks as $rolfRisk) { - $rolfRisks[] = $rolfRisk->getId(); + foreach ($measure->getRolfRisks() as $rolfRisk) { + $rolfRiskIds[] = $rolfRisk->getId(); } - $controlSoa['measure']->rolfRisks = []; - if (!empty($rolfRisks)) { - $controlSoa['measure']->rolfRisks = $this->get('anrInstanceRiskOpService')->getOperationalRisks( - $this->anr->getId(), + $instanceRisks = []; + $operationalInstanceRisks = []; + if (!empty($amvUuids)) { + $instanceRisks = $this->anrInstanceRiskService->getInstanceRisks( + $this->anr, null, - ['rolfRisks' => $rolfRisks, 'limit' => -1, 'order' => 'cacheNetRisk', 'order_direction' => 'desc'] + ['amvs' => $amvUuids, 'limit' => -1, 'order' => 'maxRisk', 'order_direction' => 'desc'] ); } - if (!empty($amvs)) { - $controlSoa['measure']->amvs = $this->get('anrInstanceRiskService')->getInstanceRisks( - $this->anr->getId(), + if (!empty($rolfRiskIds)) { + $operationalInstanceRisks = $this->anrInstanceRiskOpService->getOperationalRisks( + $this->anr, null, - ['amvs' => $amvs, 'limit' => -1, 'order' => 'maxRisk', 'order_direction' => 'desc'] + ['rolfRisks' => $rolfRiskIds, 'limit' => -1, 'order' => 'cacheNetRisk', 'order_direction' => 'desc'] ); } - if (count($controlSoa['measure']->amvs) || count($controlSoa['measure']->rolfRisks)) { - if ($controlSoa['measure']->getUuid() != $previousControlId) { + if (!empty($instanceRisks) || !empty($operationalInstanceRisks)) { + if ($measure->getUuid() !== $previousMeasureUuid) { $section->addText( - _WT( - $controlSoa['measure']->code - ) . - ' - ' . - _WT( - $controlSoa['measure']->get('label' . - $this->currentLangAnrIndex) - ), + _WT($measure->getCode()) . ' - ' . _WT($measure->getLabel($this->currentLangAnrIndex)), array_merge($this->boldFont, ['size' => 11]) ); - if (count($controlSoa['measure']->amvs)) { - $section->addText( - $this->anrTranslate('Information risks'), - $this->boldFont - ); + if (!empty($instanceRisks)) { + $section->addText($this->anrTranslate('Information risks'), $this->boldFont); $tableRiskInfo = $section->addTable($this->borderTable); $tableRiskInfo->addRow(400); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.10), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.50), $this->setColSpanCell(2, 'DFDFDF')) - ->addText( - $this->anrTranslate('Threat'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(10.00), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Vulnerability'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Treatment'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.50), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->boldFont, - $this->centerParagraph - ); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(2.10), + $this->setColSpanCell(3, 'DFDFDF') + )->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(4.50), + $this->setColSpanCell(2, 'DFDFDF') + )->addText($this->anrTranslate('Threat'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(10.00), + $this->setColSpanCell(3, 'DFDFDF') + )->addText($this->anrTranslate('Vulnerability'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(3.00), + $this->setColSpanCell(3, 'DFDFDF') + )->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Treatment'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.50), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Residual risk'), $this->boldFont, $this->centerParagraph); $tableRiskInfo->addRow(400); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - 'C', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - 'I', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->grayCell) - ->addText( - $this->anrTranslate('A'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.50), $this->grayCell) - ->addText( - $this->anrTranslate('Label'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->grayCell) - ->addText( - $this->anrTranslate('Label'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.00), $this->grayCell) + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText('C', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText('I', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->grayCell) + ->addText($this->anrTranslate('A'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.50), $this->grayCell) + ->addText($this->anrTranslate('Label'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->grayCell) + ->addText($this->anrTranslate('Label'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) ->addText( $this->anrTranslate('Existing controls'), $this->boldFont, $this->centerParagraph ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->grayCell) - ->addText( - $this->anrTranslate('Qualif.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - 'C', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - 'I', - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->grayCell) - ->addText( - $this->anrTranslate('A'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskInfo->addCell(Converter::cmToTwip(1.50), $this->continueAndGrayCell); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->grayCell) + ->addText($this->anrTranslate('Qualif.'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText('C', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText('I', $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->grayCell) + ->addText($this->anrTranslate('A'), $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(1.50), $this->continueAndGrayCell); } - if (count($controlSoa['measure']->rolfRisks)) { - $section->addText( - $this->anrTranslate('Operational risks'), - $this->boldFont - ); + if (!empty($operationalInstanceRisks)) { + $section->addText($this->anrTranslate('Operational risks'), $this->boldFont); $tableRiskOp = $section->addTable($this->borderTable); $tableRiskOp->addRow(400); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Risk description'), - $this->boldFont, - $this->centerParagraph - ); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp - ->addCell( - Converter::cmToTwip(5.50), - $this->setColSpanCell(2 + count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Inherent risk'), - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Risk description'), $this->boldFont, $this->centerParagraph); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(5.50), + $this->setColSpanCell(2 + count($opRisksImpactsScales), 'DFDFDF') + )->addText($this->anrTranslate('Inherent risk'), $this->boldFont, $this->centerParagraph); } - $tableRiskOp - ->addCell( - Converter::cmToTwip(15.00), - $this->setColSpanCell(3 + count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Net risk'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Treatment'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Residual risk'), - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(15.00), + $this->setColSpanCell(3 + count($opRisksImpactsScales), 'DFDFDF') + )->addText($this->anrTranslate('Net risk'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Treatment'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Residual risk'), $this->boldFont, $this->centerParagraph); $tableRiskOp->addRow(400, $this->tblHeader); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->continueAndGrayCell); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp - ->addCell( - Converter::cmToTwip($sizeCellImpact), - $this->setColSpanCell(count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp - ->addCell( - Converter::cmToTwip($sizeCellImpact), + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->continueAndGrayCell); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip($sizeCellImpact), $this->setColSpanCell(count($opRisksImpactsScales), 'DFDFDF') - ) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->restartAndGrayCell) - ->addText( - $this->anrTranslate('Current risk'), - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(8.00), $this->restartAndGrayCell) + )->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + } + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip($sizeCellImpact), + $this->setColSpanCell(count($opRisksImpactsScales), 'DFDFDF') + )->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndGrayCell) + ->addText($this->anrTranslate('Current risk'), $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->restartAndGrayCell) ->addText( $this->anrTranslate('Existing controls'), $this->boldFont, $this->centerParagraph ); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); - - $tableRiskOp->addRow(Converter::cmToTwip(1.00), ['tblHeader' => true]); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->continueAndGrayCell); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); + + $tableRiskOp->addRow(PhpWord\Shared\Converter::cmToTwip(1.00), ['tblHeader' => true]); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->continueAndGrayCell); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); foreach ($opRisksImpactsScales as $opRiskImpactScale) { $label = mb_substr(_WT($opRiskImpactScale['label']), 0, 3) . '.'; - $tableRiskOp - ->addCell( - Converter::cmToTwip(0.70), - array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) - ) - ->addText( - $label, - $this->boldFont, - $this->verticalCenterParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(0.70), + array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) + )->addText($label, $this->boldFont, $this->verticalCenterParagraph); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); foreach ($opRisksImpactsScales as $opRiskImpactScale) { $label = mb_substr(_WT($opRiskImpactScale['label']), 0, 3) . '.'; - $tableRiskOp - ->addCell( - Converter::cmToTwip(0.70), - array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) - ) - ->addText( - $label, - $this->boldFont, - $this->verticalCenterParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(0.70), + array_merge($this->rotate90TextCell, ['bgcolor' => 'DFDFDF']) + )->addText($label, $this->boldFont, $this->verticalCenterParagraph); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(8.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueAndGrayCell); } } - $previousControlId = $controlSoa['measure']->getUuid(); - if (!empty($controlSoa['measure']->amvs)) { + + $previousMeasureUuid = $measure->getUuid(); + if (!empty($instanceRisks)) { $impacts = ['c', 'i', 'd']; - foreach ($controlSoa['measure']->amvs as $r) { + foreach ($instanceRisks as $instanceRisk) { foreach ($impacts as $impact) { - if ($r[$impact . '_risk_enabled'] == 0) { - $r[$impact . '_risk'] = null; + if ($instanceRisk[$impact . '_risk_enabled'] === 0) { + $instanceRisk[$impact . '_risk'] = null; } } - foreach ($r as $key => $value) { - if ($value == -1) { - $r[$key] = '-'; + foreach ($instanceRisk as $key => $value) { + if ($value === -1) { + $instanceRisk[$key] = '-'; } } - $instance = $this->instanceTable->findById($r['instance']); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($instanceRisk['instance'], $this->anr); if (!$instance->getObject()->isScopeGlobal()) { $path = $instance->getHierarchyString(); } else { - $path = $instance->{ - 'name' . - $this->currentLangAnrIndex} . - ' (' . - $this->anrTranslate('Global') . - ')'; + $path = $instance->getName($this->currentLangAnrIndex) + . ' (' . $this->anrTranslate('Global') . ')'; } $tableRiskInfo->addRow(400); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($path), + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($path), $this->normalFont, $this->leftParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($instanceRisk['c_impact'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($instanceRisk['i_impact'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) + ->addText($instanceRisk['d_impact'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.50), $this->vAlignCenterCell) + ->addText( + _WT($instanceRisk['threatLabel' . $this->currentLangAnrIndex]), $this->normalFont, $this->leftParagraph ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['c_impact'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['i_impact'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) - ->addText( - $r['d_impact'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.50), $this->vAlignCenterCell) + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText($instanceRisk['threatRate'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) ->addText( - _WT($r['threatLabel' . $this->currentLangAnrIndex]), + _WT($instanceRisk['vulnLabel' . $this->currentLangAnrIndex]), $this->normalFont, $this->leftParagraph ); - $tableRiskInfo->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $r['threatRate'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($r['vulnLabel' . $this->currentLangAnrIndex]), - $this->normalFont, - $this->leftParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($r['comment']), - $this->normalFont, - $this->leftParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - $r['vulnerabilityRate'], - $this->normalFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['c_risk'])) - ->addText( - $r['c_risk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['i_risk'])) - ->addText( - $r['i_risk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.00), $this->setBgColorCell($r['d_risk'])) - ->addText( - $r['d_risk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskInfo->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - $this->getKindfofMeasureLabel($r['kindOfMeasure']), + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($instanceRisk['comment']), $this->normalFont, $this->leftParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText($instanceRisk['vulnerabilityRate'], $this->normalFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($instanceRisk['c_risk']) + )->addText($instanceRisk['c_risk'], $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($instanceRisk['i_risk']) + )->addText($instanceRisk['i_risk'], $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($instanceRisk['d_risk']) + )->addText($instanceRisk['d_risk'], $this->boldFont, $this->centerParagraph); + $tableRiskInfo->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText( + InstanceRiskOpSuperClass::getTreatmentNameByType($instanceRisk['kindOfMeasure']), $this->normalFont, $this->leftParagraph ); - $tableRiskInfo->addCell(Converter::cmToTwip(1.50), $this->setBgColorCell($r['target_risk'])) - ->addText( - $r['target_risk'], - $this->boldFont, - $this->centerParagraph - ); + $tableRiskInfo->addCell( + PhpWord\Shared\Converter::cmToTwip(1.50), + $this->setBgColorCell($instanceRisk['target_risk']) + )->addText($instanceRisk['target_risk'], $this->boldFont, $this->centerParagraph); } } - if (count($controlSoa['measure']->rolfRisks)) { - $kindOfRisks = ['cacheBrutRisk', 'cacheNetRisk', 'cacheTargetedRisk']; - - foreach ($controlSoa['measure']->rolfRisks as $r) { - foreach ($r as $key => $value) { - if ($value == -1) { - $r[$key] = '-'; + if (!empty($operationalInstanceRisks)) { + foreach ($operationalInstanceRisks as $riskOp) { + foreach ($riskOp as $key => $value) { + if ($value === -1) { + $riskOp[$key] = '-'; } } - $instance = $this->instanceTable->findById($r['instanceInfos']['id']); + $instance = $this->instanceTable->findById($riskOp['instanceInfos']['id']); $path = $instance->getHierarchyString(); $tableRiskOp->addRow(400); - $tableRiskOp->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($path), - $this->normalFont, - $this->leftParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($path), $this->normalFont, $this->leftParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) ->addText( - _WT($r['label' . $this->currentLangAnrIndex]), + _WT($riskOp['label' . $this->currentLangAnrIndex]), $this->normalFont, $this->leftParagraph ); - if ($this->anr->showRolfBrut == 1) { - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $r['brutProb'], - $this->normalFont, - $this->centerParagraph - ); + if ($this->anr->showRolfBrut()) { + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($riskOp['brutProb'], $this->normalFont, $this->centerParagraph); foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $tableRiskOp->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) ->addText( - $r['scales'][$opRiskImpactScale['id']]['brutValue'] !== -1 ? - $r['scales'][$opRiskImpactScale['id']]['brutValue'] : + $riskOp['scales'][$opRiskImpactScale['id']]['brutValue'] !== -1 ? + $riskOp['scales'][$opRiskImpactScale['id']]['brutValue'] : '-', $this->normalFont, $this->centerParagraph ); } - $tableRiskOp - ->addCell( - Converter::cmToTwip(1.00), - $this->setBgColorCell($r['cacheBrutRisk'], false) - ) - ->addText( - $r['cacheBrutRisk'], - $this->boldFont, - $this->centerParagraph - ); + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($riskOp['cacheBrutRisk'], false) + )->addText($riskOp['cacheBrutRisk'], $this->boldFont, $this->centerParagraph); } - $tableRiskOp->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $r['netProb'], - $this->normalFont, - $this->centerParagraph - ); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($riskOp['netProb'], $this->normalFont, $this->centerParagraph); foreach ($opRisksImpactsScales as $opRiskImpactScale) { - $tableRiskOp->addCell(Converter::cmToTwip(0.70), $this->vAlignCenterCell) + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(0.70), $this->vAlignCenterCell) ->addText( - $r['scales'][$opRiskImpactScale['id']]['netValue'] !== -1 ? - $r['scales'][$opRiskImpactScale['id']]['netValue'] : - '-', + $riskOp['scales'][$opRiskImpactScale['id']]['netValue'] !== -1 + ? $riskOp['scales'][$opRiskImpactScale['id']]['netValue'] + : '-', $this->normalFont, $this->centerParagraph ); } - $tableRiskOp - ->addCell( - Converter::cmToTwip(1.00), - $this->setBgColorCell($r['cacheNetRisk'], false) - ) - ->addText( - $r['cacheNetRisk'], - $this->boldFont, - $this->centerParagraph - ); - $tableRiskOp->addCell(Converter::cmToTwip(8.00), $this->vAlignCenterCell) - ->addText( - _WT($r['comment']), + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(1.00), + $this->setBgColorCell($riskOp['cacheNetRisk'], false) + )->addText($riskOp['cacheNetRisk'], $this->boldFont, $this->centerParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->vAlignCenterCell) + ->addText(_WT($riskOp['comment']), $this->normalFont, $this->leftParagraph); + $tableRiskOp->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->vAlignCenterCell) + ->addText( + InstanceRiskOpSuperClass::getTreatmentNameByType($riskOp['kindOfMeasure']), $this->normalFont, $this->leftParagraph ); - $tableRiskOp->addCell(Converter::cmToTwip(2.00), $this->vAlignCenterCell) - ->addText( - $this->getKindfofMeasureLabel($r['kindOfMeasure']), - $this->normalFont, - $this->leftParagraph - ); - $cacheTargetedRisk = $r['cacheTargetedRisk'] == '-' ? - $r['cacheNetRisk'] : - $r['cacheTargetedRisk']; - $tableRiskOp - ->addCell( - Converter::cmToTwip(2.00), - $this->setBgColorCell($cacheTargetedRisk, false) - ) - ->addText( - $cacheTargetedRisk, - $this->boldFont, - $this->centerParagraph - ); + $cacheTargetedRisk = $riskOp['cacheTargetedRisk'] === '-' + ? $riskOp['cacheNetRisk'] + : $riskOp['cacheTargetedRisk']; + $tableRiskOp->addCell( + PhpWord\Shared\Converter::cmToTwip(2.00), + $this->setBgColorCell($cacheTargetedRisk, false) + )->addText($cacheTargetedRisk, $this->boldFont, $this->centerParagraph); } } $section->addTextBreak(); @@ -4471,287 +3081,181 @@ protected function generateTableRisksByControl($referential) } /** - * Generates the Processing Activities Record's General Informations data + * Generates the Processing Activities Record's General Information data. + * * @return mixed|string The WordXml data generated */ - protected function generateTableRecordGDPR($recordId) + private function generateTableRecordGDPR($recordId) { - $recordTable = $this->get('recordService')->get('table'); - $recordEntity = $recordTable->getEntity($recordId); + $record = $this->recordTable->findById((int)$recordId); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $tableWord->getSettings()->setUpdateFields(true); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Name'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($recordEntity->get('label')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Name'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($record->getLabel()), $this->normalFont, $this->leftParagraph); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Creation date'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Creation date'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) ->addText( - ($recordEntity->get('createdAt') ? - strftime("%d-%m-%Y", $recordEntity->get('createdAt')->getTimeStamp()) : - "" - ), + $record->getCreatedAt() ? strftime("%d-%m-%Y", $record->getCreatedAt()->getTimeStamp()) : '', $this->normalFont, $this->leftParagraph ); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Update date'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) ->addText( - $this->anrTranslate('Update date'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - ($recordEntity->get('updatedAt') ? - strftime("%d-%m-%Y", $recordEntity->get('updatedAt')->getTimeStamp()) : - "" - ), + $record->getUpdatedAt() ? strftime("%d-%m-%Y", $record->getUpdatedAt()->getTimeStamp()) : '', $this->normalFont, $this->leftParagraph ); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Purpose(s)'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($recordEntity->get('purposes')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Purpose(s)'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($record->getPurposes()), $this->normalFont, $this->leftParagraph); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Security measures'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($recordEntity->get('secMeasures')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Security measures'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($record->getSecMeasures()), $this->normalFont, $this->leftParagraph); return $this->getWordXmlFromWordObject($tableWord); } /** - * Generates the Processing Activities Record's Joint Controllers data + * Generates the Processing Activities Record's Joint Controllers data. + * * @return mixed|string The WordXml data generated */ - protected function generateTableRecordActors($recordId) + private function generateTableRecordActors($recordId) { - $recordTable = $this->get('recordService')->get('table'); - $recordEntity = $recordTable->getEntity($recordId); - $jointControllers = $recordEntity->get('jointControllers'); + $record = $this->recordTable->findById((int)$recordId); + $jointControllers = $record->getJointControllers(); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); //header if array is not empty $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Actor'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Name'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Contact'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Actor'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Name'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Contact'), $this->boldFont, $this->centerParagraph); $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Controller'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Controller'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recordEntity->get('controller') ? - $recordEntity->get('controller')->get('label') : - ""), + _WT($record->getController() ? $record->getController()->getLabel() : ''), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recordEntity->get('controller') ? - $recordEntity->get('controller')->get('contact') : - ""), + _WT($record->getController() ? $record->getController()->getContact() : ''), $this->normalFont, $this->leftParagraph ); $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Representative'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - $this->anrTranslate('Representative'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) - ->addText( - _WT($recordEntity->get('representative') ? - $recordEntity->get('representative')->get('label') : - ""), + _WT($record->get('representative') ? $record->get('representative')->get('label') : ""), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recordEntity->get('representative') ? - $recordEntity->get('representative')->get('contact') : - ""), + _WT($record->get('representative') ? $record->get('representative')->get('contact') : ""), $this->normalFont, $this->leftParagraph ); $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Data protection officer'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Data protection officer'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recordEntity->get('dpo') ? - $recordEntity->get('dpo')->get('label') : - ""), + _WT($record->get('dpo') ? $record->get('dpo')->get('label') : ""), $this->normalFont, $this->leftParagraph ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) ->addText( - _WT($recordEntity->get('dpo') ? - $recordEntity->get('dpo')->get('contact') : - ""), + _WT($record->get('dpo') ? $record->get('dpo')->get('contact') : ""), $this->normalFont, $this->leftParagraph ); $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Joint controllers'), - $this->boldFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Joint controllers'), $this->boldFont, $this->leftParagraph); - if (count($jointControllers)) { + if (!empty($jointControllers)) { $i = 0; foreach ($jointControllers as $jc) { - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) - ->addText( - _WT($jc->get('label')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) - ->addText( - _WT($jc->get('contact')), - $this->normalFont, - $this->leftParagraph - ); - if ($i != count($jointControllers) - 1) { + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) + ->addText(_WT($jc->get('label')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) + ->addText(_WT($jc->get('contact')), $this->normalFont, $this->leftParagraph); + if ($i !== count($jointControllers) - 1) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell); } ++$i; } } else { - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell); } return $this->getWordXmlFromWordObject($tableWord); } /** - * Generates the Processing Activities Record's Personal data data + * Generates the Processing Activities Record's Personal data. + * * @return mixed|string The WordXml data generated */ - protected function generateTableRecordPersonalData($recordId) + private function generateTableRecordPersonalData($recordId) { - $recordTable = $this->get('recordService')->get('table'); - $recordEntity = $recordTable->getEntity($recordId); + $recordEntity = $this->recordTable->getEntity($recordId); $personalData = $recordEntity->get('personalData'); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); - if (count($personalData)) { + if (!empty($personalData)) { $table = $section->addTable($this->borderTable); //header if array is not empty $table->addRow(400); - $table->addCell(Converter::cmToTwip(3.60), $this->grayCell) - ->addText( - $this->anrTranslate('Data subject'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->grayCell) - ->addText( - $this->anrTranslate('Personal data categories'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->grayCell) - ->addText( - $this->anrTranslate('Description'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->grayCell) - ->addText( - $this->anrTranslate('Retention period'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->grayCell) - ->addText( - $this->anrTranslate('Retention period description'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->grayCell) + ->addText($this->anrTranslate('Data subject'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->grayCell) + ->addText($this->anrTranslate('Personal data categories'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->grayCell) + ->addText($this->anrTranslate('Description'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->grayCell) + ->addText($this->anrTranslate('Retention period'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->grayCell) + ->addText($this->anrTranslate('Retention period description'), $this->boldFont, $this->centerParagraph); foreach ($personalData as $pd) { $table->addRow(400); @@ -4760,40 +3264,24 @@ protected function generateTableRecordPersonalData($recordId) $dataCategories .= $dc->get('label') . "\n"; } $retentionPeriod = $pd->get('retentionPeriod') . ' '; - if ($pd->get('retentionPeriodMode') == 0) { + if ($pd->get('retentionPeriodMode') === 0) { $retentionPeriod .= $this->anrTranslate('day(s)'); } else { - if ($pd->get('retentionPeriodMode') == 1) { + if ($pd->get('retentionPeriodMode') === 1) { $retentionPeriod .= $this->anrTranslate('month(s)'); } else { $retentionPeriod .= $this->anrTranslate('year(s)'); - } - } - $table->addCell(Converter::cmToTwip(3.60), $this->vAlignCenterCell) - ->addText( - _WT($pd->get('dataSubject')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->vAlignCenterCell) - ->addText( - _WT($dataCategories), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->vAlignCenterCell) - ->addText( - _WT($pd->get('description')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->vAlignCenterCell) - ->addText( - _WT($retentionPeriod), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(3.60), $this->vAlignCenterCell) + } + } + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->vAlignCenterCell) + ->addText(_WT($pd->get('dataSubject')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->vAlignCenterCell) + ->addText(_WT($dataCategories), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->vAlignCenterCell) + ->addText(_WT($pd->get('description')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->vAlignCenterCell) + ->addText(_WT($retentionPeriod), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.60), $this->vAlignCenterCell) ->addText( _WT($pd->get('retentionPeriodDescription')), $this->normalFont, @@ -4801,7 +3289,7 @@ protected function generateTableRecordPersonalData($recordId) ); } } else { - $table = $section->addText( + $section->addText( $this->anrTranslate('No category of personal data'), $this->normalFont, $this->leftParagraph @@ -4815,69 +3303,42 @@ protected function generateTableRecordPersonalData($recordId) * Generates the Processing Activities Record's Recipients data * @return mixed|string The WordXml data generated */ - protected function generateTableRecordRecipients($recordId) + private function generateTableRecordRecipients($recordId) { - $recordTable = $this->get('recordService')->get('table'); - $recordEntity = $recordTable->getEntity($recordId); + $recordEntity = $this->recordTable->getEntity($recordId); $recipients = $recordEntity->get('recipients'); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); - if (count($recipients)) { + if (!empty($recipients)) { $table = $section->addTable($this->borderTable); //header if array is not empty $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Recipient'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Type'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(8.00), $this->grayCell) - ->addText( - $this->anrTranslate('Description'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Recipient'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Type'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->grayCell) + ->addText($this->anrTranslate('Description'), $this->boldFont, $this->centerParagraph); foreach ($recipients as $r) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) - ->addText( - _WT($r->get('label')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) + ->addText(_WT($r->get('label')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) ->addText( - $r->get('type') == 0 ? - $this->anrTranslate('internal') : - $this->anrTranslate('external'), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(8.00), $this->vAlignCenterCell) - ->addText( - _WT($r->get('description')), + $r->getType() === 0 ? $this->anrTranslate('internal') : $this->anrTranslate('external'), $this->normalFont, $this->leftParagraph ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(8.00), $this->vAlignCenterCell) + ->addText(_WT($r->get('description')), $this->normalFont, $this->leftParagraph); } } else { - $table = $section->addText( - $this->anrTranslate('No recipient'), - $this->normalFont, - $this->leftParagraph - ); + $section->addText($this->anrTranslate('No recipient'), $this->normalFont, $this->leftParagraph); } return $this->getWordXmlFromWordObject($tableWord); @@ -4887,14 +3348,13 @@ protected function generateTableRecordRecipients($recordId) * Generates the Processing Activities Record's International Transfers data * @return mixed|string The WordXml data generated */ - protected function generateTableRecordInternationalTransfers($recordId) + private function generateTableRecordInternationalTransfers($recordId) { - $recordTable = $this->get('recordService')->get('table'); - $recordEntity = $recordTable->getEntity($recordId); + $recordEntity = $this->recordTable->getEntity($recordId); $internationalTransfers = $recordEntity->get('internationalTransfers'); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); if (count($internationalTransfers)) { @@ -4902,60 +3362,28 @@ protected function generateTableRecordInternationalTransfers($recordId) //header if array is not empty $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.50), $this->grayCell) - ->addText( - $this->anrTranslate('Organisation'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->grayCell) - ->addText( - $this->anrTranslate('Description'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->grayCell) - ->addText( - $this->anrTranslate('Country'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->grayCell) - ->addText( - $this->anrTranslate('Documents'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->grayCell) + ->addText($this->anrTranslate('Organisation'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->grayCell) + ->addText($this->anrTranslate('Description'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->grayCell) + ->addText($this->anrTranslate('Country'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->grayCell) + ->addText($this->anrTranslate('Documents'), $this->boldFont, $this->centerParagraph); foreach ($internationalTransfers as $it) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.50), $this->vAlignCenterCell) - ->addText( - _WT($it->get('organisation')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->vAlignCenterCell) - ->addText( - _WT($it->get('description')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->vAlignCenterCell) - ->addText( - _WT($it->get('country')), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(4.50), $this->vAlignCenterCell) - ->addText( - _WT($it->get('documents')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->vAlignCenterCell) + ->addText(_WT($it->get('organisation')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->vAlignCenterCell) + ->addText(_WT($it->get('description')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->vAlignCenterCell) + ->addText(_WT($it->get('country')), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.50), $this->vAlignCenterCell) + ->addText(_WT($it->get('documents')), $this->normalFont, $this->leftParagraph); } } else { - $table = $section->addText( + $section->addText( $this->anrTranslate('No international transfer'), $this->normalFont, $this->leftParagraph @@ -4970,154 +3398,87 @@ protected function generateTableRecordInternationalTransfers($recordId) * Generates the Processing Activities Record's Processors data * @return mixed|string The WordXml data generated */ - protected function generateTableRecordProcessors($recordId) + private function generateTableRecordProcessors($recordId) { - $recordTable = $this->get('recordService')->get('table'); - $recordEntity = $recordTable->getEntity($recordId); + $recordEntity = $this->recordTable->getEntity($recordId); $processors = $recordEntity->get('processors'); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); if (count($processors) < 1) { - $section->addText( - $this->anrTranslate('No processor'), - $this->normalFont, - $this->leftParagraph - ); + $section->addText($this->anrTranslate('No processor'), $this->normalFont, $this->leftParagraph); } foreach ($processors as $p) { //create section - $section->addText( - _WT($p->get('label')), - $this->boldFont - ); + $section->addText(_WT($p->get('label')), $this->boldFont); $table = $section->addTable($this->borderTable); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Name'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($p->get('label')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Name'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($p->get('label')), $this->normalFont, $this->leftParagraph); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Contact'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($p->get('contact')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Contact'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($p->get('contact')), $this->normalFont, $this->leftParagraph); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Activities'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($p->get('activities')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Activities'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($p->get('activities')), $this->normalFont, $this->leftParagraph); $table->addRow(400); - $table->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Security measures'), - $this->boldFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(14.00), $this->vAlignCenterCell) - ->addText( - _WT($p->get('secMeasures')), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Security measures'), $this->boldFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(14.00), $this->vAlignCenterCell) + ->addText(_WT($p->get('secMeasures')), $this->normalFont, $this->leftParagraph); $section->addTextBreak(1); - $section->addText( - $this->anrTranslate('Actors'), - $this->boldFont - ); + $section->addText($this->anrTranslate('Actors'), $this->boldFont); $tableActor = $section->addTable($this->borderTable); $tableActor->addRow(400); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->grayCell) - ->addText( - $this->anrTranslate('Actor'), - $this->boldFont, - $this->centerParagraph - ); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->grayCell) - ->addText( - $this->anrTranslate('Name'), - $this->boldFont, - $this->centerParagraph - ); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->grayCell) - ->addText( - $this->anrTranslate('Contact'), - $this->boldFont, - $this->centerParagraph - ); + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->grayCell) + ->addText($this->anrTranslate('Actor'), $this->boldFont, $this->centerParagraph); + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->grayCell) + ->addText($this->anrTranslate('Name'), $this->boldFont, $this->centerParagraph); + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->grayCell) + ->addText($this->anrTranslate('Contact'), $this->boldFont, $this->centerParagraph); $tableActor->addRow(400); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->grayCell) + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->grayCell) ->addText( $this->anrTranslate('Representative'), $this->boldFont, $this->leftParagraph ); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) ->addText( - _WT($p->get('representative') ? - $p->get('representative')->get('label') : - ""), + _WT($p->get('representative') ? $p->get('representative')->get('label') : ""), $this->normalFont, $this->leftParagraph ); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) ->addText( - _WT($p->get('representative') ? - $p->get('representative')->get('contact') : - ""), + _WT($p->get('representative') ? $p->get('representative')->get('contact') : ""), $this->normalFont, $this->leftParagraph ); $tableActor->addRow(400); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->grayCell) - ->addText( - $this->anrTranslate('Data protection officer'), - $this->boldFont, - $this->leftParagraph - ); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->grayCell) + ->addText($this->anrTranslate('Data protection officer'), $this->boldFont, $this->leftParagraph); + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) ->addText( - _WT($p->get('dpo') ? - $p->get('dpo')->get('label') : - ""), + _WT($p->get('dpo') ? $p->get('dpo')->get('label') : ""), $this->normalFont, $this->leftParagraph ); - $tableActor->addCell(Converter::cmToTwip(10.00), $this->vAlignCenterCell) + $tableActor->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->vAlignCenterCell) ->addText( - _WT($p->get('dpo') ? - $p->get('dpo')->get('contact') : - ""), + _WT($p->get('dpo') ? $p->get('dpo')->get('contact') : ""), $this->normalFont, $this->leftParagraph ); @@ -5132,71 +3493,52 @@ protected function generateTableRecordProcessors($recordId) * Generates all the Processing Activities Record in the anr * @return mixed|string The WordXml data generated */ - protected function generateTableAllRecordsGDPR() + private function generateTableAllRecordsGDPR() { - $recordTable = $this->get('recordService')->get('table'); - $recordEntities = $recordTable->getEntityByFields(['anr' => $this->anr->getId()]); + $recordEntities = $this->recordTable->getEntityByFields(['anr' => $this->anr->getId()]); $result = ''; foreach ($recordEntities as $recordEntity) { - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(1, $this->titleFont); - $section->addTitle( - _WT($recordEntity->get('label')), - 1 - ); + $section->addTitle(_WT($recordEntity->get('label')), 1); $result .= $this->getWordXmlFromWordObject($tableWord); $result .= $this->generateTableRecordGDPR($recordEntity->id); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(2, $this->titleFont); - $section->addTitle( - $this->anrTranslate('Actors'), - 2 - ); + $section->addTitle($this->anrTranslate('Actors'), 2); $result .= $this->getWordXmlFromWordObject($tableWord); $result .= $this->generateTableRecordActors($recordEntity->id); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(2, $this->titleFont); - $section->addTitle( - $this->anrTranslate('Categories of personal data'), - 2 - ); + $section->addTitle($this->anrTranslate('Categories of personal data'), 2); $result .= $this->getWordXmlFromWordObject($tableWord); $result .= $this->generateTableRecordPersonalData($recordEntity->id); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(2, $this->titleFont); - $section->addTitle( - $this->anrTranslate('Recipients'), - 2 - ); + $section->addTitle($this->anrTranslate('Recipients'), 2); $result .= $this->getWordXmlFromWordObject($tableWord); $result .= $this->generateTableRecordRecipients($recordEntity->id); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(2, $this->titleFont); - $section->addTitle( - $this->anrTranslate('International transfers'), - 2 - ); + $section->addTitle($this->anrTranslate('International transfers'), 2); $result .= $this->getWordXmlFromWordObject($tableWord); $result .= $this->generateTableRecordInternationalTransfers($recordEntity->id); //create section - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(2, $this->titleFont); - $section->addTitle( - $this->anrTranslate('Processors'), - 2 - ); + $section->addTitle($this->anrTranslate('Processors'), 2); $result .= $this->getWordXmlFromWordObject($tableWord); $result .= $this->generateTableRecordProcessors($recordEntity->id); } @@ -5208,49 +3550,36 @@ protected function generateTableAllRecordsGDPR() * Generate the impacts appreciation table data * @return mixed|string The WordXml table data */ - - protected function generateImpactsAppreciation() + private function generateImpactsAppreciation() { - // TODO: C'est moche, optimiser - $allInstances = $this->instanceTable->findByAnrAndOrderByParams($this->anr, ['i.position' => 'ASC']); - /** @var Instance[] $instances */ - $instances = array_filter($allInstances, function ($ins) { - return ($ins->getConfidentiality() > -1 && $ins->getInheritedConfidentiality() === 0) || - ($ins->getIntegrity() > -1 && $ins->getInheritedIntegrity() === 0) || - ($ins->getAvailability() > -1 && $ins->getInheritedAvailability() === 0); - }); + $instances = $this->instanceTable->findInstancesByAnrWithEvaluationAndNotInheritedOrderBy( + $this->anr, + ['i.position' => 'ASC'] + ); $impacts = ['c', 'i', 'd']; - $instanceCriteria = Instance::getAvailableScalesCriteria(); + $instanceCriteria = Entity\Instance::getAvailableScalesCriteria(); - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); //header - if (\count($instances)) { + if (!empty($instances)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(9.00), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Impact'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(9.00), $this->setColSpanCell(3, 'DFDFDF')) - ->addText( - $this->anrTranslate('Consequences'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(9.00), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Impact'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(9.00), $this->setColSpanCell(3, 'DFDFDF')) + ->addText($this->anrTranslate('Consequences'), $this->boldFont, $this->centerParagraph); } $globalObjectsUuids = []; foreach ($instances as $instance) { /* Check if the global object is already added. */ - if (\in_array($instance->getObject()->getUuid(), $globalObjectsUuids, true)) { + if (in_array($instance->getObject()->getUuid(), $globalObjectsUuids, true)) { continue; } - $instanceConsequences = $this->anrInstanceConsequenceService->getConsequences($instance, true); + $instanceConsequences = $this->anrInstanceConsequenceService->getConsequencesData($instance, true); //delete scale type C,I and D // set the correct order in the deliverable. not perfect but work @@ -5258,7 +3587,6 @@ protected function generateImpactsAppreciation() foreach ($instanceConsequences as $keyConsequence => $instanceConsequence) { if ($instanceConsequence['scaleImpactType'] < 4) { unset($instanceConsequences[$keyConsequence]); - $impactsConsequences[$instanceConsequence['scaleImpactType'] - 1] = $instanceConsequence; } $impactsConsequences[$instanceConsequence['scaleImpactType'] - 1] = $instanceConsequence; } @@ -5271,9 +3599,9 @@ protected function generateImpactsAppreciation() if ($instanceConsequence[$impact . '_risk'] >= 0) { if (!$headerImpact && !$headerConsequence) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(16), $this->setColSpanCell(6, 'DBE5F1')) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(16), $this->setColSpanCell(6, 'DBE5F1')) ->addText( - _WT($instance->{'getName' . $this->currentLangAnrIndex}()), + _WT($instance->getName($this->currentLangAnrIndex)), $this->boldFont, $this->leftParagraph ); @@ -5286,57 +3614,41 @@ protected function generateImpactsAppreciation() if (!$headerConsequence) { $comment = $impactsConsequences[$keyImpact]['comments'][ $instance->{'get' . $instanceCriteria[$impact]}() !== -1 - ? $instance->{'get' . $instanceCriteria[$impact]}() - : 0 - ]; + ? $instance->{'get' . $instanceCriteria[$impact]}() + : 0 + ] ?? ''; $translatedImpact = ucfirst($impact); if ($impact === 'd') { $translatedImpact = ucfirst($this->anrTranslate('A')); } - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndCenterCell) - ->addText( - $translatedImpact, - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.00), $this->restartAndCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndCenterCell) + ->addText($translatedImpact, $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->restartAndCenterCell) ->addText( $instance->{'get' . $instanceCriteria[$impact]}(), $this->boldFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(5.00), $this->restartAndCenterCell) - ->addText( - _WT($comment), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->restartAndCenterCell) + ->addText(_WT($comment), $this->normalFont, $this->leftParagraph); } else { - $table->addCell(Converter::cmToTwip(1.00), $this->continueCell); - $table->addCell(Converter::cmToTwip(1.00), $this->continueCell); - $table->addCell(Converter::cmToTwip(5.00), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.00), $this->continueCell); } $comment = $instanceConsequence['comments'][ $instanceConsequence[$impact . '_risk'] !== -1 ? $instanceConsequence[$impact . '_risk'] : 0 - ]; - $table->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ] ?? ''; + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) ->addText( _WT($instanceConsequence['scaleImpactTypeDescription' . $this->currentLangAnrIndex]), $this->boldFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(1.00), $this->vAlignCenterCell) - ->addText( - $instanceConsequence[$impact . '_risk'], - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(7.00), $this->vAlignCenterCell) - ->addText( - _WT($comment), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.00), $this->vAlignCenterCell) + ->addText($instanceConsequence[$impact . '_risk'], $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(7.00), $this->vAlignCenterCell) + ->addText(_WT($comment), $this->normalFont, $this->leftParagraph); $headerConsequence = true; } @@ -5348,126 +3660,85 @@ protected function generateImpactsAppreciation() } /** - * Generate the threats table data - * @param bool $fullGen Whether or not to generate the full table (all but normal) or just the normal threats - * @return mixed|string The WordXml generated data + * Generate the threats table data. + * + * @param bool $fullGen Whether to generate the full table (all but normal) or just the normal threats. + * + * @return mixed|string The WordXml generated data. */ - protected function generateThreatsTable($fullGen = false) + private function generateThreatsTable($fullGen = false) { - $threats = $this->threatService->getList(1, 0, null, null, ['anr' => $this->anr->getId()]); - - $tableWord = new PhpWord(); - $section = $tableWord->addSection(); - $table = $section->addTable($this->borderTable); - + /** @var Entity\Threat[] $threats */ + $threats = $this->threatTable->findByAnr($this->anr); $nbThreats = 0; foreach ($threats as $threat) { - if (($threat['trend'] != 1) || $fullGen) { + if ($fullGen || $threat->getTrend() !== 1) { $nbThreats++; } } + $tableWord = new PhpWord\PhpWord(); + $section = $tableWord->addSection(); + $table = $section->addTable($this->borderTable); + if ($nbThreats > 0) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(7.60), $this->grayCell) - ->addText( - $this->anrTranslate('Threat'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.50), $this->grayCell) - ->addText( - $this->anrTranslate('CIA'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.70), $this->grayCell) - ->addText( - $this->anrTranslate('Tend.'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(1.60), $this->grayCell) - ->addText( - $this->anrTranslate('Prob.'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.60), $this->grayCell) - ->addText( - $this->anrTranslate('Comment'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(7.60), $this->grayCell) + ->addText($this->anrTranslate('Threat'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.50), $this->grayCell) + ->addText($this->anrTranslate('CIA'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.70), $this->grayCell) + ->addText($this->anrTranslate('Tend.'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.60), $this->grayCell) + ->addText($this->anrTranslate('Prob.'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.60), $this->grayCell) + ->addText($this->anrTranslate('Comment'), $this->boldFont, $this->centerParagraph); } foreach ($threats as $threat) { - if (($threat['trend'] != 1) || $fullGen) { // All but normal + if ($fullGen || $threat->getTrend() !== 1) { $table->addRow(400); - $table->addCell(Converter::cmToTwip(5.85), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(5.85), $this->vAlignCenterCell) ->addText( - _WT($threat['label' . $this->currentLangAnrIndex]), + _WT($threat->getLabel($this->currentLangAnrIndex)), $this->normalFont, $this->leftParagraph ); // CID $cid = ''; - if ($threat['c']) { + if ($threat->getConfidentiality()) { $cid .= 'C'; } - if ($threat['i']) { + if ($threat->getIntegrity()) { $cid .= 'I'; } - if ($threat['a']) { + if ($threat->getAvailability()) { $cid .= $this->anrTranslate('A'); } - $table->addCell(Converter::cmToTwip(1.50), $this->vAlignCenterCell) - ->addText( - $cid, - $this->normalFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.50), $this->vAlignCenterCell) + ->addText($cid, $this->normalFont, $this->centerParagraph); // Trend - switch ($threat['trend']) { - case 0: - $trend = '-'; - break; - case 1: - $trend = 'n'; - break; - case 2: - $trend = '+'; - break; - case 3: - $trend = '++'; - break; - default: - $trend = ''; - break; - } - $table->addCell(Converter::cmToTwip(1.70), $this->vAlignCenterCell) - ->addText( - $trend, - $this->normalFont, - $this->centerParagraph - ); + $trend = match ($threat->getTrend()) { + 0 => '-', + 1 => 'n', + 2 => '+', + 3 => '++', + default => '', + }; + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.70), $this->vAlignCenterCell) + ->addText($trend, $this->normalFont, $this->centerParagraph); // Pre-Q - $qual = $threat['qualification'] >= 0 ? $threat['qualification'] : ''; - $table->addCell(Converter::cmToTwip(1.60), $this->vAlignCenterCell) + $table->addCell(PhpWord\Shared\Converter::cmToTwip(1.60), $this->vAlignCenterCell) ->addText( - $qual, + $threat->getQualification() >= 0 ? $threat->getQualification() : '', $this->normalFont, $this->centerParagraph ); - $table->addCell(Converter::cmToTwip(6.60), $this->vAlignCenterCell) - ->addText( - _WT($threat['comment']), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.60), $this->vAlignCenterCell) + ->addText(_WT($threat->getComment()), $this->normalFont, $this->leftParagraph); } } @@ -5478,7 +3749,7 @@ protected function generateThreatsTable($fullGen = false) * Generate the owner table data * @return mixed|string The WordXml generated data */ - protected function generateOwnersTable() + private function generateOwnersTable() { $allOwners = $this->instanceRiskOwnerTable->findByAnr($this->anr); $globalObjectsUuids = []; @@ -5491,17 +3762,13 @@ protected function generateOwnersTable() . $ir->getThreat()->getUuid() . $ir->getVulnerability()->getUuid(); - if (\in_array($uniqueKey, $globalObjectsUuids, true)) { + if (in_array($uniqueKey, $globalObjectsUuids, true)) { continue; } if ($ir->getInstance()->getObject()->isScopeGlobal()) { - $asset = $ir->getInstance()->{ - 'getName' . - $this->currentLangAnrIndex}() . - ' (' . - $this->anrTranslate('Global') . - ')'; + $asset = $ir->getInstance()->getName($this->currentLangAnrIndex) . ' (' + . $this->anrTranslate('Global') . ')'; $globalObjectsUuids[] = $uniqueKey; } else { $asset = $ir->getInstance()->getHierarchyString(); @@ -5523,70 +3790,38 @@ protected function generateOwnersTable() } } - $tableWord = new PhpWord(); + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $table = $section->addTable($this->borderTable); if (!empty($risksByOwner)) { $table->addRow(400, $this->tblHeader); - $table->addCell(Converter::cmToTwip(2.00), $this->grayCell) - ->addText( - $this->anrTranslate('Owner'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(6.00), $this->grayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - $table->addCell(Converter::cmToTwip(10.00), $this->setColSpanCell(2, 'DFDFDF')) - ->addText( - $this->anrTranslate('Risk'), - $this->boldFont, - $this->centerParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->grayCell) + ->addText($this->anrTranslate('Owner'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->grayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->setColSpanCell(2, 'DFDFDF')) + ->addText($this->anrTranslate('Risk'), $this->boldFont, $this->centerParagraph); foreach ($risksByOwner as $owner => $risks) { $isOwnerHeader = true; foreach ($risks as $risk) { $table->addRow(400); if ($isOwnerHeader) { - $table->addCell(Converter::cmToTwip(2.00), $this->restartAndCenterCell) - ->addText( - _WT($owner), - $this->boldFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->restartAndCenterCell) + ->addText(_WT($owner), $this->boldFont, $this->leftParagraph); } else { - $table->addCell(Converter::cmToTwip(2.00), $this->continueCell); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(2.00), $this->continueCell); } - $table->addCell(Converter::cmToTwip(6.00), $this->vAlignCenterCell) - ->addText( - _WT($risk['asset']), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(6.00), $this->vAlignCenterCell) + ->addText(_WT($risk['asset']), $this->normalFont, $this->leftParagraph); if (isset($risk['threat'])) { - $table->addCell(Converter::cmToTwip(3.00), $this->vAlignCenterCell) - ->addText( - _WT($risk['threat']), - $this->normalFont, - $this->leftParagraph - ); - $table->addCell(Converter::cmToTwip(7.00), $this->vAlignCenterCell) - ->addText( - _WT($risk['vulnerability']), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(3.00), $this->vAlignCenterCell) + ->addText(_WT($risk['threat']), $this->normalFont, $this->leftParagraph); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(7.00), $this->vAlignCenterCell) + ->addText(_WT($risk['vulnerability']), $this->normalFont, $this->leftParagraph); } else { - $table->addCell(Converter::cmToTwip(10.00), $this->setColSpanCell(2)) - ->addText( - _WT($risk['risk']), - $this->normalFont, - $this->leftParagraph - ); + $table->addCell(PhpWord\Shared\Converter::cmToTwip(10.00), $this->setColSpanCell(2)) + ->addText(_WT($risk['risk']), $this->normalFont, $this->leftParagraph); } $isOwnerHeader = false; } @@ -5597,161 +3832,111 @@ protected function generateOwnersTable() } /** - * Generate the asset context table data + * Generate the asset context table data. + * * @return mixed|string The WordXml generated data */ - protected function generateAssetContextTable() + private function generateAssetContextTable() { - $allInstances = $this->instanceTable->findByAnrId($this->anr->getId()); - $allMetadatas = $this->metadatasOnInstancesTable->findByAnr($this->anr); - $translations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $this->anr, - [Translation::INSTANCE_METADATA, Translation::ANR_METADATAS_ON_INSTANCES], - $this->configService->getActiveLanguageCodes()[$this->anr->getLanguage()] - ); - $assetUuids = []; - foreach ($allMetadatas as $metadata) { - $translationLabel = $translations[$metadata->getLabelTranslationKey()] ?? null; - $headersMetadata[] = $translationLabel !== null ? $translationLabel->getValue() : ''; + /** @var Entity\AnrInstanceMetadataField[] $anrMetadataFields */ + $anrMetadataFields = $this->anrInstanceMetadataFieldTable->findByAnr($this->anr); + $metadataFieldsHeaders = []; + foreach ($anrMetadataFields as $anrMetadataField) { + $metadataFieldsHeaders[] = $anrMetadataField->getLabel(); } - if (!isset($headersMetadata)) { - return; + if (empty($metadataFieldsHeaders)) { + return null; } - $sizeColumn = 13 / count($headersMetadata); - $tableWord = new PhpWord(); + $sizeColumn = 13 / count($metadataFieldsHeaders); + + $tableWord = new PhpWord\PhpWord(); $section = $tableWord->addSection(); $tableWord->addTitleStyle(3, $this->titleFont); - foreach ($allInstances as $instance) { + $assetUuids = []; + /** @var Entity\Instance[] $instances */ + $instances = $this->instanceTable->findByAnr($this->anr); + foreach ($instances as $instance) { $assetUuid = $instance->getAsset()->getUuid(); - if (\in_array($assetUuid, $assetUuids, true)) { + if (in_array($assetUuid, $assetUuids, true)) { continue; } $assetUuids[] = $assetUuid; - $typeAsset = ($instance->getAsset()->getType() == 1) ? 'PrimaryAssets' : 'SecondaryAssets'; - $assetLabel = $instance->{'getName' . $this->currentLangAnrIndex}(); + $typeAsset = $instance->getAsset()->isPrimary() ? 'PrimaryAssets' : 'SecondaryAssets'; + $assetLabel = $instance->getName($this->currentLangAnrIndex); if ($instance->getObject()->isScopeGlobal()) { - $assetLabel = $assetLabel . ' (' . $this->anrTranslate('Global') . ')'; + $assetLabel .= ' (' . $this->anrTranslate('Global') . ')'; } - $instanceMetadatas = $instance->getInstanceMetadatas(); if (!isset(${'table' . $typeAsset})) { $section->addTitle( - $this->anrTranslate( - ($instance->getAsset()->getType() == 1) ? - 'Primary assets' : - 'Secondary assets' - ), + $this->anrTranslate($instance->getAsset()->isPrimary() ? 'Primary assets' : 'Secondary assets'), 3 ); ${'table' . $typeAsset} = $section->addTable($this->borderTable); ${'table' . $typeAsset}->addRow(400, $this->tblHeader); - ${'table' . $typeAsset}->addCell(Converter::cmToTwip(4.00), $this->grayCell) - ->addText( - $this->anrTranslate('Asset'), - $this->boldFont, - $this->centerParagraph - ); - foreach ($headersMetadata as $headerMetadata) { - ${'table' . $typeAsset}->addCell(Converter::cmToTwip($sizeColumn), $this->grayCell) - ->addText( - _WT($headerMetadata), - $this->boldFont, - $this->centerParagraph - ); + ${'table' . $typeAsset}->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->grayCell) + ->addText($this->anrTranslate('Asset'), $this->boldFont, $this->centerParagraph); + foreach ($metadataFieldsHeaders as $headerMetadata) { + ${'table' . $typeAsset}->addCell(PhpWord\Shared\Converter::cmToTwip($sizeColumn), $this->grayCell) + ->addText(_WT($headerMetadata), $this->boldFont, $this->centerParagraph); } } ${'table' . $typeAsset}->addRow(400); - ${'table' . $typeAsset}->addCell(Converter::cmToTwip(4.00), $this->vAlignCenterCell) - ->addText( - _WT($assetLabel), - $this->normalFont, - $this->leftParagraph - ); + ${'table' . $typeAsset}->addCell(PhpWord\Shared\Converter::cmToTwip(4.00), $this->vAlignCenterCell) + ->addText(_WT($assetLabel), $this->normalFont, $this->leftParagraph); - foreach ($allMetadatas as $metadata) { - if ($instanceMetadatas) { + $instanceMetadata = $instance->getInstanceMetadata(); + foreach ($anrMetadataFields as $anrMetadataField) { + if (!$instanceMetadata->isEmpty()) { $metadataFiltered = array_filter( - $instanceMetadatas->toArray(), - function ($im) use ($metadata) { - return $metadata->getId() == $im->getMetadata()->getId(); + $instanceMetadata->toArray(), + static function ($im) use ($anrMetadataField) { + /** @var Entity\InstanceMetadata $im */ + return $anrMetadataField->getId() === $im->getAnrInstanceMetadataField()->getId(); } ); } $translationComment = null; - if (count($metadataFiltered) > 0) { + if (!empty($metadataFiltered)) { $translationComment = $translations[reset($metadataFiltered)->getCommentTranslationKey()] ?? null; } - ${'table' . $typeAsset}->addCell(Converter::cmToTwip($sizeColumn), $this->vAlignCenterCell) - ->addText( - $translationComment !== null ? _WT($translationComment->getValue()) : '', - $this->normalFont, - $this->leftParagraph - ); + ${'table' . $typeAsset}->addCell( + PhpWord\Shared\Converter::cmToTwip($sizeColumn), + $this->vAlignCenterCell + )->addText( + $translationComment !== null ? _WT($translationComment->getValue()) : '', + $this->normalFont, + $this->leftParagraph + ); } } return $this->getWordXmlFromWordObject($tableWord); } - /** - * Retrieves the label of kindOfMeasure - * @param int $kindOfMeasure value - * @return string kindOfMeasure label - */ - private function getKindfofMeasureLabel($kindOfMeasure) - { - switch ($kindOfMeasure) { - case 1: - $kindfofMeasureLabel = "Reduction"; - break; - case 2: - $kindfofMeasureLabel = "Denied"; - break; - case 3: - $kindfofMeasureLabel = "Accepted"; - break; - case 4: - $kindfofMeasureLabel = "Shared"; - break; - default: - $kindfofMeasureLabel = "Not treated"; - } - - return $this->anrTranslate($kindfofMeasureLabel); - } - - /** - * Retrieves the company name to display within the document - * @return string The company name - */ - public function getCompanyName() - { - $client = current($this->clientTable->fetchAll()); - - return $client['name']; - } - /** * Generates WordXml data from HTML. + * * @param string $input HTML input + * * @return string WordXml data */ - protected function generateWordXmlFromHtml($input) + private function generateWordXmlFromHtml($input) { // Process trix caveats $input = html_entity_decode($input); $input = str_replace( - ['<', '>', '&','
'], - ['[escape_lt]', '[escape_gt]', '[escape_amp]',''], + ['<', '>', '&', '
'], + ['[escape_lt]', '[escape_gt]', '[escape_amp]', ''], $input ); - while (strpos($input, '
    ') !== false) { + while (str_contains($input, '
      ')) { if (preg_match_all("'
        (.*?)
      '", $input, $groups)) { foreach ($groups as $group) { $value1 = preg_replace( @@ -5765,12 +3950,12 @@ protected function generateWordXmlFromHtml($input) } } - while (strpos($input, '
        ') !== false) { + while (str_contains($input, '
          ')) { if (preg_match_all("'
            (.*?)
          '", $input, $groups)) { foreach ($groups as $group) { $index = 0; - while (strpos($group[0], '
        1. ') !== false) { - $index += 1; + while (str_contains($group[0], '
        2. ')) { + ++$index; $group[0] = preg_replace( ["'
        3. '", "'
        4. '"], ["  [$index] ", ''], @@ -5784,38 +3969,39 @@ protected function generateWordXmlFromHtml($input) } // Turn it into word data - $phpWord = new PhpWord(); + $phpWord = new PhpWord\PhpWord(); $section = $phpWord->addSection(); - Html::addHtml($section, $input); + PhpWord\Shared\Html::addHtml($section, $input); return $this->getWordXmlFromWordObject($phpWord); } /** * Generates the instances tree + * * @param array $elements instances risks array * @param int $parentId id of parent_Root * * @return array */ - protected function buildTree($elements, $parentId) + private function buildTree($elements, $parentId) { $branch = []; foreach ($elements as $element => $value) { - if ($value['parent'] == $parentId) { + if ($value['parent'] === $parentId) { $children = $this->buildTree($elements, $element); if ($children) { - usort($children, function ($a, $b) { + usort($children, static function ($a, $b) { return $a['position'] <=> $b['position']; }); $value['children'] = $children; } $branch[] = $value; - } elseif (!isset($value['parent']) && $parentId == $element) { + } elseif (!isset($value['parent']) && $parentId === $element) { $branch[] = $value; } } - usort($branch, function ($a, $b) { + usort($branch, static function ($a, $b) { return $a['position'] <=> $b['position']; }); @@ -5824,21 +4010,21 @@ protected function buildTree($elements, $parentId) /** * Generates a single-level array from multilevel array + * * @param array $multiLevelArray + * * @return array */ - protected function singleLevelArray($multiLevelArray) + private function singleLevelArray($multiLevelArray) { $singleLevelArray = []; foreach ($multiLevelArray as $a) { + $singleLevelArray[] = $a; if (isset($a['children'])) { - $singleLevelArray[] = $a; $children_array = $this->singleLevelArray($a['children']); foreach ($children_array as $children) { $singleLevelArray[] = $children; } - } else { - $singleLevelArray[] = $a; } } @@ -5847,13 +4033,13 @@ protected function singleLevelArray($multiLevelArray) /** * Retrieves the WordXml data from a generated PhpWord Object - * @param PhpWord $phpWord The PhpWord Object + * * @return string The WordXml data */ - protected function getWordXmlFromWordObject($phpWord) + private function getWordXmlFromWordObject(PhpWord\PhpWord $phpWord) { - $part = new Document(); - $part->setParentWriter(new Word2007($phpWord)); + $part = new PhpWord\Writer\Word2007\Part\Document(); + $part->setParentWriter(new PhpWord\Writer\Word2007($phpWord)); $docXml = $part->write(); $matches = []; $regex = '/(.*)/is'; @@ -5864,14 +4050,15 @@ protected function getWordXmlFromWordObject($phpWord) ['<', '>', '&'], $matches[1] ); + return $matches[1]; } } - private function getObjectInstancePath(RecommandationRisk $recommendationRisk): string + private function getObjectInstancePath(Entity\RecommendationRisk $recommendationRisk): string { if ($recommendationRisk->hasGlobalObjectRelation()) { - return $recommendationRisk->getInstance()->{'getName' . $recommendationRisk->getAnr()->getLanguage()}() + return $recommendationRisk->getInstance()->getName($recommendationRisk->getAnr()->getLanguage()) . ' (' . $this->anrTranslate('Global') . ')'; } @@ -5884,8 +4071,9 @@ private function getInstancePathFromHierarchy(array $instanceHierarchyArray): st } } -function _WT($input) +function _WT(string $input) { - $input = htmlspecialchars(trim($input), ENT_COMPAT, 'UTF-8'); + $input = htmlspecialchars(trim($input), ENT_COMPAT); + return str_replace("\n", '', $input); } diff --git a/src/Service/DeliverableGenerationServiceFactory.php b/src/Service/DeliverableGenerationServiceFactory.php deleted file mode 100755 index 46bb602d..00000000 --- a/src/Service/DeliverableGenerationServiceFactory.php +++ /dev/null @@ -1,58 +0,0 @@ - Delivery::class, - 'table' => Table\DeliveryTable::class, - 'deliveryModelService' => DeliveriesModelsService::class, - 'clientTable' => Table\ClientTable::class, - 'anrTable' => Table\AnrTable::class, - 'scaleService' => Service\AnrScaleService::class, - 'scaleTypeService' => Service\AnrScaleTypeService::class, - 'scaleCommentService' => Service\AnrScaleCommentService::class, - 'operationalRiskScaleService' => Service\OperationalRiskScaleService::class, - 'questionService' => Service\AnrQuestionService::class, - 'questionChoiceService' => Service\AnrQuestionChoiceService::class, - 'interviewService' => Service\AnrInterviewService::class, - 'threatService' => Service\AnrThreatService::class, - 'cartoRiskService' => Service\AnrCartoRiskService::class, - 'instanceTable' => Table\InstanceTable::class, - 'instanceRiskTable' => Table\InstanceRiskTable::class, - 'instanceRiskOpTable' => Table\InstanceRiskOpTable::class, - 'soaService' => Service\SoaService::class, - 'soaScaleCommentTable' => Table\SoaScaleCommentTable::class, - 'measureService' => Service\AnrMeasureService::class, - 'anrInstanceRiskOpService' => Service\AnrInstanceRiskOpService::class, - 'anrInstanceRiskService' => Service\AnrInstanceRiskService::class, - 'recordService' => Service\AnrRecordService::class, - 'anrInstanceConsequenceService' => Service\AnrInstanceConsequenceService::class, - 'translateService' => TranslateService::class, - 'instanceRiskOwnerTable' => Table\InstanceRiskOwnerTable::class, - 'recommendationRiskTable' => Table\RecommandationRiskTable::class, - 'recommendationHistoricTable' => Table\RecommendationHistoricTable::class, - 'metadatasOnInstancesTable' => Table\AnrMetadatasOnInstancesTable::class, - 'translationTable' => Table\TranslationTable::class, - 'configService' => ConfigService::class, - - ]; -} diff --git a/src/Service/InstanceMetadataService.php b/src/Service/InstanceMetadataService.php index 38166681..0931b7c5 100644 --- a/src/Service/InstanceMetadataService.php +++ b/src/Service/InstanceMetadataService.php @@ -1,258 +1,119 @@ anrTable = $anrTable; - $this->instanceMetadataTable = $instanceMetadataTable; - $this->instanceTable = $instanceTable; - $this->anrMetadatasOnInstancesTable = $anrMetadatasOnInstancesTable; - $this->translationTable = $translationTable; - $this->configService = $configService; $this->connectedUser = $connectedUserService->getConnectedUser(); } - - /** - * @param int $anrId - * @param int $instanceId - * @param array $data - * - * @return array - * @throws EntityNotFoundException - * @throws ORMException - * @throws OptimisticLockException - */ - public function createInstanceMetadata($anrId, $instanceId, $data): array - { - $instance = $this->instanceTable->findById($instanceId); - /** @var Anr $anr */ - $anr = $this->anrTable->findById($anrId); - $returnValue = []; - foreach ($data['metadata'] as $inputData) { - $labelTranslationKey = (string)Uuid::uuid4(); - $metadata = $this->anrMetadatasOnInstancesTable - ->findById((int)$inputData['id']); - $instanceMetadata = (new InstanceMetadata()) - ->setInstance($instance) - ->setMetadata($metadata) - ->setCommentTranslationKey($labelTranslationKey) - ->setCreator($this->connectedUser->getEmail()); - - $instancesBrothers = $this->instanceTable->findGlobalBrothersByAnrAndInstance($anr, $instance); - foreach ($instancesBrothers as $instanceBrother) { - $newInstanceMetadata = (new InstanceMetadata()) - ->setInstance($instanceBrother) - ->setMetadata($metadata) - ->setCommentTranslationKey($labelTranslationKey) - ->setCreator($this->connectedUser->getEmail()); - $this->instanceMetadataTable->save($newInstanceMetadata); - $returnValue[] = $newInstanceMetadata->getId(); - } - - $this->instanceMetadataTable->save($instanceMetadata); - $returnValue[] = $instanceMetadata->getId(); - - foreach ($inputData['instanceMetadata'] as $lang => $commentText) { - $translation = $this->createTranslationObject( - $anr, - Translation::INSTANCE_METADATA, - $labelTranslationKey, - $lang, - (string)$commentText - ); - $this->translationTable->save($translation); - } - } - return $returnValue; - } - - /** - * @param int $anrId - * @param int $instanceId - * @param string $language - * - * @return array - * @throws EntityNotFoundException - * @throws ORMException - * @throws OptimisticLockException - */ - public function getInstancesMetadatas(int $anrId, int $instanceId, string $language = null): array + public function getInstancesMetadata(Entity\Anr $anr, int $instanceId): array { $result = []; - $anr = $this->anrTable->findById($anrId); - $metadatasList = $this->anrMetadatasOnInstancesTable->findByAnr($anr); - $instance = $this->instanceTable->findById($instanceId); - $instancesMetadatas = $this->instanceMetadataTable->findByInstance($instance); - if ($language === null) { - $language = $this->getAnrLanguageCode($anr); - } - - $translations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::INSTANCE_METADATA, Translation::ANR_METADATAS_ON_INSTANCES], - $language - ); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findByIdAndAnr($instanceId, $anr); - foreach ($metadatasList as $metadata) { - $translationLabel = $translations[$metadata->getLabelTranslationKey()] ?? null; - $result[$metadata->getId()]= [ - 'id' => $metadata->getId(), - $language => $translationLabel !== null ? $translationLabel->getValue() : '', - 'isDeletable' => $metadata->isDeletable(), - 'instanceMetadata' => [], + $instanceMetadataByMetadataFieldId = []; + foreach ($instance->getInstanceMetadata() as $instanceMetadata) { + $metadataFieldId = $instanceMetadata->getAnrInstanceMetadataField()->getId(); + $instanceMetadataByMetadataFieldId[$metadataFieldId] = [ + 'id' => $instanceMetadata->getId(), + 'metadataId' => $metadataFieldId, + $anr->getLanguageCode() => $instanceMetadata->getComment(), ]; } - foreach ($instancesMetadatas as $index => $instanceMetadata) { - $translationComment = $translations[$instanceMetadata->getCommentTranslationKey()] ?? null; - $result[$instanceMetadata->getMetadata()->getId()]['instanceMetadata']= [ - 'id' => $instanceMetadata->getId(), - 'metadataId' => $instanceMetadata->getMetadata()->getId(), - $language => $translationComment !== null ? $translationComment->getValue() : '', + + foreach ($anr->getAnrInstanceMetadataFields() as $metadataField) { + $metadataFieldId = $metadataField->getId(); + $result[$metadataFieldId] = [ + 'id' => $metadataFieldId, + $anr->getLanguageCode() => $metadataField->getLabel(), + 'isDeletable' => $metadataField->isDeletable(), + 'instanceMetadata' => $instanceMetadataByMetadataFieldId[$metadataFieldId] ?? [], ]; } return $result; } - /** - * @param int $id - * - * @throws EntityNotFoundException - */ - public function deleteInstanceMetadata(int $id) + public function create(Entity\Anr $anr, int $instanceId, array $data): Entity\InstanceMetadata { - $instanceMetadataToDelete = $this->instanceMetadataTable->findById($id); - $anr = $instanceMetadataToDelete->getAnr(); - $instance = $instanceMetadataToDelete->getInstance(); - if ($instanceMetadataToDelete === null) { - throw new EntityNotFoundException(sprintf('Instance Metadata with ID %d is not found', $id)); - } - - $this->instanceMetadataTable->remove($instanceMetadataToDelete); - $instancesBrothers = $this->instanceTable->findGlobalBrothersByAnrAndInstance($anr, $instance); - //the translation is not used anymore - if (count($instancesBrothers)==0) { - $translationsKeys[] = $instanceMetadataToDelete->getCommentTranslationKey(); + /** @var Entity\Instance $instance */ + $instance = $this->instanceTable->findById($instanceId); + $metadataFieldData = current($data['metadata']); + $instanceMetadataComment = $metadataFieldData['instanceMetadata'][$anr->getLanguageCode()] ?? ''; + /** @var Entity\AnrInstanceMetadataField $metadataField */ + $metadataField = $this->anrInstanceMetadataFieldTable->findByIdAndAnr((int)$metadataFieldData['id'], $anr); + $instanceMetadata = (new Entity\InstanceMetadata()) + ->setInstance($instance) + ->setAnrInstanceMetadataField($metadataField) + ->setComment($instanceMetadataComment) + ->setCreator($this->connectedUser->getEmail()); - if (!empty($translationsKeys)) { - $this->translationTable->deleteListByKeys($translationsKeys); - } - } - } + /* Create the same context instance metadata records for the global instance's siblings. */ + $siblingInstances = $this->instanceTable->findGlobalSiblingsByAnrAndInstance($anr, $instance); + foreach ($siblingInstances as $siblingInstance) { + $siblingInstanceMetadata = (new Entity\InstanceMetadata()) + ->setInstance($siblingInstance) + ->setAnrInstanceMetadataField($metadataField) + ->setComment($instanceMetadataComment) + ->setCreator($this->connectedUser->getEmail()); - /** - * @param int $anrId - * @param int $id - * @param string¦null $language - * - * @throws EntityNotFoundException - */ - public function getInstanceMetadata(int $anrId, int $id, string $language = null): array - { - $anr = $this->anrTable->findById($anrId); - $instanceMetadata = $this->instanceMetadataTable->findById($id); - if ($language === null) { - $language = $this->getAnrLanguageCode($anr); + $this->instanceMetadataTable->save($siblingInstanceMetadata, false); } - $translations = $this->translationTable->findByAnrTypesAndLanguageIndexedByKey( - $anr, - [Translation::INSTANCE_METADATA], - $language - ); + $this->instanceMetadataTable->save($instanceMetadata); - $translationLabel = $translations[$instanceMetadata->getCommentTranslationKey()] ?? null; - return [ - 'id' => $instanceMetadata->getId(), - $language => $translationLabel !== null ? $translationLabel->getValue() : '', - ]; + return $instanceMetadata; } - public function update(int $id, array $data): int + public function update(Entity\Anr $anr, int $id, array $data): Entity\InstanceMetadata { - /** @var InstanceMetadata $instanceMetadata */ - $instanceMetadata = $this->instanceMetadataTable->findById($id); + /** @var Entity\InstanceMetadata $instanceMetadata */ + $instanceMetadata = $this->instanceMetadataTable->findByIdAndAnr($id, $anr); - $anr = $instanceMetadata->getInstance()->getAnr(); + $commentValue = $data[$anr->getLanguageCode()] ?? ''; + $instanceMetadata->setComment($commentValue) + ->setUpdater($this->connectedUser->getEmail()); - if (!empty($data)) { - $languageCode = $data['language'] ?? $this->getAnrLanguageCode($anr); - $translationKey = $instanceMetadata->getCommentTranslationKey(); - if (!empty($translationKey)) { - $translation = $this->translationTable - ->findByAnrKeyAndLanguage($anr, $translationKey, $languageCode); - $translation->setValue($data[$languageCode]); - $this->translationTable->save($translation, false); + /* Update the context instance metadata comment for the global instance's siblings. */ + $siblingInstances = $this->instanceTable->findGlobalSiblingsByAnrAndInstance( + $anr, + $instanceMetadata->getInstance() + ); + foreach ($siblingInstances as $siblingInstance) { + $siblingInstanceMetadata = $this->instanceMetadataTable->findByInstanceAndMetadataField( + $siblingInstance, + $instanceMetadata->getAnrInstanceMetadataField() + ); + if ($siblingInstanceMetadata !== null) { + $siblingInstanceMetadata->setComment($commentValue) + ->setUpdater($this->connectedUser->getEmail()); + + $this->instanceMetadataTable->save($siblingInstanceMetadata, false); } } - $this->instanceMetadataTable->save($instanceMetadata); - return $instanceMetadata->getId(); - } - - protected function getAnrLanguageCode(Anr $anr): string - { - return $this->configService->getActiveLanguageCodes()[$anr->getLanguage()]; - } + $this->instanceMetadataTable->save($instanceMetadata); - protected function createTranslationObject( - Anr $anr, - string $type, - string $key, - string $lang, - string $value - ): Translation { - return (new Translation()) - ->setAnr($anr) - ->setType($type) - ->setKey($key) - ->setLang($lang) - ->setValue($value) - ->setCreator($this->connectedUser->getEmail()); + return $instanceMetadata; } } diff --git a/src/Service/InstanceRiskOwnerService.php b/src/Service/InstanceRiskOwnerService.php index 31a304fc..45dcd19a 100644 --- a/src/Service/InstanceRiskOwnerService.php +++ b/src/Service/InstanceRiskOwnerService.php @@ -1,30 +1,75 @@ connectedUser = $connectedUserService->getConnectedUser(); + } + + public function create(Anr $anr, string $ownerName, bool $saveIdDb = false): InstanceRiskOwner + { + $instanceRiskOwner = (new InstanceRiskOwner()) + ->setAnr($anr) + ->setName($ownerName) + ->setCreator($this->connectedUser->getEmail()); + + $this->instanceRiskOwnerTable->save($instanceRiskOwner, $saveIdDb); + + return $instanceRiskOwner; + } + + public function getOrCreateInstanceRiskOwner(Anr $sourceAnr, Anr $anr, string $ownerName): InstanceRiskOwner { - $this->anrTable = $anrTable; - $this->instanceRiskOwnerTable = $instanceRiskOwnerTable; + if (!isset($this->cachedData['isInstanceRiskOwnersCacheLoaded'])) { + $this->cachedData['isInstanceRiskOwnersCacheLoaded'] = true; + /** @var InstanceRiskOwner $instanceRiskOwner */ + foreach ($this->instanceRiskOwnerTable->findByAnr($sourceAnr) as $instanceRiskOwner) { + $this->cachedData['instanceRiskOwners'][$instanceRiskOwner->getName()] = $instanceRiskOwner; + } + } + if (!isset($this->cachedData['instanceRiskOwners'][$ownerName])) { + $this->cachedData['instanceRiskOwners'][$ownerName] = $this->create($anr, $ownerName); + } + + return $this->cachedData['instanceRiskOwners'][$ownerName]; + } + + public function processRiskOwnerNameAndAssign(string $ownerName, InstanceRisk|InstanceRiskOp $instanceRisk): void + { + if (empty($ownerName)) { + $instanceRisk->setInstanceRiskOwner(null); + } else { + /** @var Anr $anr */ + $anr = $instanceRisk->getAnr(); + $instanceRiskOwner = $this->getOrCreateInstanceRiskOwner($anr, $anr, $ownerName); + $instanceRisk->setInstanceRiskOwner($instanceRiskOwner); + } } - public function getList(int $anrId, array $params = []): array + public function getList(Anr $anr, array $params = []): array { - $anr = $this->anrTable->findById($anrId); $result = []; foreach ($this->instanceRiskOwnerTable->findByAnrAndFilterParams($anr, $params) as $instanceRiskOwner) { $result[] = [ diff --git a/src/Service/Model/Entity/AbstractServiceModelEntity.php b/src/Service/Model/Entity/AbstractServiceModelEntity.php index 7ef085db..d03af3a1 100755 --- a/src/Service/Model/Entity/AbstractServiceModelEntity.php +++ b/src/Service/Model/Entity/AbstractServiceModelEntity.php @@ -7,45 +7,52 @@ namespace Monarc\FrontOffice\Service\Model\Entity; +use Monarc\Core\Service\Model\Entity\AbstractServiceModelEntity as CoreAbstractServiceModelEntity; +use Monarc\FrontOffice\Entity\Anr; use Monarc\FrontOffice\Model\DbCli; -use Monarc\FrontOffice\Model\Table\AnrTable; +use Monarc\FrontOffice\Table\AnrTable; use Laminas\Http\PhpEnvironment\Request; use Laminas\Router\Http\TreeRouteStack; use Laminas\Router\RouteMatch; /** - * Class AbstractServiceModelEntity - * @package Monarc\Core\Service\Model\Entity + * TODO: drop this class as soon as all the AbstractEntity is removed. */ -abstract class AbstractServiceModelEntity extends \Monarc\Core\Service\Model\Entity\AbstractServiceModelEntity +abstract class AbstractServiceModelEntity extends CoreAbstractServiceModelEntity { + private static ?int $anrLanguage = null; + protected $ressources = [ 'setDbAdapter' => DbCli::class, ]; public function getDefaultLanguage($sm) { + if (self::$anrLanguage !== null) { + return self::$anrLanguage; + } + /** @var Request $request */ $request = $sm->get('Request'); - if(!$request instanceof \Laminas\Console\Request){ + if (!$request instanceof \Laminas\Console\Request) { /** @var TreeRouteStack $router */ $router = $sm->get('Router'); /** @var RouteMatch $match */ $match = $router->match($request); - if($match){ - $anrId = $match->getParam('anrid', false); - - if ($anrId) { + if ($match) { + $anrId = $match->getParam('anrid'); + if ($anrId !== null) { /** @var AnrTable $anrTable */ $anrTable = $sm->get(AnrTable::class); - $anr = $anrTable->getEntity($anrId); + /** @var Anr $anr */ + $anr = $anrTable->findById((int)$anrId); + self::$anrLanguage = $anr->getLanguage(); - if ($anr->get('language')) { - return $anr->get('language'); - } + return self::$anrLanguage; } } } + return parent::getDefaultLanguage($sm); } } diff --git a/src/Service/Model/Entity/AmvServiceModelEntity.php b/src/Service/Model/Entity/AmvServiceModelEntity.php deleted file mode 100755 index 214310b6..00000000 --- a/src/Service/Model/Entity/AmvServiceModelEntity.php +++ /dev/null @@ -1,18 +0,0 @@ - 'Monarc\Core\Model\Table\ModelTable', - 'entity' => 'Monarc\Core\Model\Entity\Model', - 'anrService' => 'Monarc\Core\Service\AnrService', - 'anrTable' => 'Monarc\Core\Model\Table\AnrTable', - 'instanceRiskTable' => 'Monarc\Core\Model\Table\InstanceRiskTable', - 'instanceRiskOpTable' => 'Monarc\Core\Model\Table\InstanceRiskOpTable', - 'MonarcObjectTable' => 'Monarc\Core\Model\Table\MonarcObjectTable', - 'amvTable' => 'Monarc\Core\Model\Table\AmvTable', - 'clientTable' => 'Monarc\FrontOffice\Model\Table\ClientTable' - ]; -} diff --git a/src/Service/ObjectExportService.php b/src/Service/ObjectExportService.php deleted file mode 100644 index 3c62ecec..00000000 --- a/src/Service/ObjectExportService.php +++ /dev/null @@ -1,279 +0,0 @@ -monarcObjectTable = $monarcObjectTable; - $this->objectObjectTable = $objectObjectTable; - $this->assetExportService = $assetExportService; - $this->configService = $configService; - } - - /** - * @throws EntityNotFoundException - * @throws Exception - */ - public function generateExportArray(string $uuid, Anr $anr, bool $withEval = false) - { - $monarcObject = $this->monarcObjectTable->findByAnrAndUuid($anr, $uuid); - - $result = [ - 'monarc_version' => $this->configService->getAppVersion()['appVersion'], - 'type' => 'object', - 'object' => [ - 'uuid' => $monarcObject->getUuid(), - 'mode' => $monarcObject->getMode(), - 'scope' => $monarcObject->getScope(), - 'name1' => $monarcObject->getName(1), - 'name2' => $monarcObject->getName(2), - 'name3' => $monarcObject->getName(3), - 'name4' => $monarcObject->getName(4), - 'label1' => $monarcObject->getLabel(1), - 'label2' => $monarcObject->getLabel(2), - 'label3' => $monarcObject->getLabel(3), - 'label4' => $monarcObject->getLabel(4), - 'disponibility' => $monarcObject->getDisponibility(), - 'position' => $monarcObject->getPosition(), - 'category' => null, - 'asset' => null, - 'rolfTag' => null, - ], - 'categories' => [], - 'asset' => null, - 'rolfTags' => [], - 'rolfRisks' => [], - 'children' => [], - ]; - - if ($monarcObject->getCategory() !== null) { - $result['object']['category'] = $monarcObject->getCategory()->getId(); - $result['categories'] = $this->getCategoryDataWithItsParents($monarcObject->getCategory()); - } - - if ($monarcObject->getAsset() !== null) { - $result['object']['asset'] = $monarcObject->getAsset()->getUuid(); - $result['asset'] = $this->assetExportService->generateExportArray( - $monarcObject->getAsset()->getUuid(), - $anr, - $withEval - ); - } - - $rolfTag = $monarcObject->getRolfTag(); - if ($rolfTag !== null) { - $result['object']['rolfTag'] = $rolfTag->getId(); - $result['rolfTags'][$rolfTag->getId()] = [ - 'id' => $rolfTag->getId(), - 'code' => $rolfTag->getCode(), - 'label1' => $rolfTag->getLabel(1), - 'label2' => $rolfTag->getLabel(2), - 'label3' => $rolfTag->getLabel(3), - 'label4' => $rolfTag->getLabel(4), - 'risks' => [], - ]; - - $rolfRisks = $rolfTag->getRisks(); - if (!empty($rolfRisks)) { - foreach ($rolfRisks as $rolfRisk) { - $rolfRiskId = $rolfRisk->getId(); - $result['rolfTags'][$rolfTag->getId()]['risks'][$rolfRiskId] = $rolfRiskId; - $result['rolfRisks'][$rolfRiskId] = [ - 'id' => $rolfRiskId, - 'code' => $rolfRisk->getCode(), - 'label1' => $rolfRisk->getLabel(1), - 'label2' => $rolfRisk->getLabel(2), - 'label3' => $rolfRisk->getLabel(3), - 'label4' => $rolfRisk->getLabel(4), - 'description1' => $rolfRisk->getDescription(1), - 'description2' => $rolfRisk->getDescription(2), - 'description3' => $rolfRisk->getDescription(3), - 'description4' => $rolfRisk->getDescription(4), - 'measures' => [], - ]; - foreach ($rolfRisk->getMeasures() as $measure) { - $result['rolfRisks'][$rolfRiskId]['measures'][] = [ - 'uuid' => $measure->getUuid(), - 'category' => $measure->getCategory() - ? [ - 'id' => $measure->getCategory()->getId(), - 'status' => $measure->getCategory()->getStatus(), - 'label1' => $measure->getCategory()->getlabel1(), - 'label2' => $measure->getCategory()->getlabel2(), - 'label3' => $measure->getCategory()->getlabel3(), - 'label4' => $measure->getCategory()->getlabel4(), - ] - : null, - 'referential' => [ - 'uuid' => $measure->getReferential()->getUuid(), - 'label1' => $measure->getReferential()->getLabel1(), - 'label2' => $measure->getReferential()->getLabel2(), - 'label3' => $measure->getReferential()->getLabel3(), - 'label4' => $measure->getReferential()->getLabel4(), - ], - 'code' => $measure->getCode(), - 'label1' => $measure->getLabel1(), - 'label2' => $measure->getLabel2(), - 'label3' => $measure->getLabel3(), - 'label4' => $measure->getLabel4(), - ]; - } - } - } - } - - $children = $this->objectObjectTable->findChildrenByFather($monarcObject, ['position' => 'ASC']); - if (!empty($children)) { - $position = 1; - foreach ($children as $child) { - $childObjectUuid = $child->getChild()->getUuid(); - $result['children'][$childObjectUuid] = $this->generateExportArray( - $childObjectUuid, - $anr, - $withEval - ); - $result['children'][$childObjectUuid]['object']['position'] = $position++; - } - } - - return $result; - } - - private function getCategoryDataWithItsParents(ObjectCategorySuperClass $objectCategory): array - { - $objectCategories[$objectCategory->getId()] = [ - 'id' => $objectCategory->getId(), - 'label1' => $objectCategory->getLabel(1), - 'label2' => $objectCategory->getLabel(2), - 'label3' => $objectCategory->getLabel(3), - 'label4' => $objectCategory->getLabel(4), - 'parent' => null, - ]; - if ($objectCategory->getParent() !== null) { - $objectCategories[$objectCategory->getId()]['parent'] = $objectCategory->getParent()->getId(); - $objectCategories += $this->getCategoryDataWithItsParents($objectCategory->getParent()); - } - - return $objectCategories; - } - - /** - * @throws EntityNotFoundException - * @throws Exception - */ - public function generateExportMospArray(string $uuid, Anr $anr): array - { - $languageIndex = $anr->getLanguage(); - $languageCode = $this->configService->getLanguageCodes()[$languageIndex]; - - $monarcObject = $this->monarcObjectTable->findByAnrAndUuid($anr, $uuid); - - $result = [ - 'object' => [ - 'uuid' => $monarcObject->getUuid(), - 'scope' => $monarcObject->getScopeName(), - 'name' => $monarcObject->getName($languageIndex), - 'label' => $monarcObject->getLabel($languageIndex), - 'language' => $languageCode, - 'version' => 1, - ], - 'asset' => null, - 'rolfRisks' => [], - 'rolfTags' => [], - 'children' => [], - ]; - - if ($monarcObject->getAsset() !== null) { - $result['asset'] = $this->assetExportService->generateExportMospArray( - $monarcObject->getAsset()->getUuid(), - $anr, - $languageCode - ); - } - - $rolfTag = $monarcObject->getRolfTag(); - if ($rolfTag !== null) { - $result['rolfTags'][] = [ - 'code' => $rolfTag->getCode(), - 'label' => $rolfTag->getLabel($languageIndex), - ]; - - if (!empty($rolfTag->getRisks())) { - foreach ($rolfTag->getRisks() as $rolfRisk) { - $measuresData = []; - foreach ($rolfRisk->getMeasures() as $measure) { - $measuresData[] = [ - 'uuid' => $measure->getUuid(), - 'code' => $measure->getCode(), - 'label' => $measure->{'getLabel' . $languageIndex}(), - 'category' => $measure->getCategory()->{'getLabel' . $languageIndex}(), - 'referential' => $measure->getReferential()->getUuid(), - 'referential_label' => $measure->getReferential()->{'getLabel' . $languageIndex}(), - ]; - } - - $result['rolfRisks'][] = [ - 'code' => $rolfRisk->getCode(), - 'label' => $rolfRisk->getLabel($languageIndex), - 'description' => $rolfRisk->getDescription($languageIndex), - 'measures' => $measuresData, - ]; - } - } - } - - $children = $this->objectObjectTable->findChildrenByFather($monarcObject, ['position' => 'ASC']); - if (!empty($children)) { - foreach ($children as $child) { - $result['children'][] = $this->generateExportMospArray( - $child->getChild()->getUuid(), - $anr - ); - } - } - - return ['object' => $result]; - } - - /** - * @throws EntityNotFoundException - * @throws NonUniqueResultException - */ - public function generateExportFileName(string $uuid, Anr $anr, bool $isForMosp = false): string - { - $monarcObject = $this->monarcObjectTable->findByAnrAndUuid($anr, $uuid); - - return preg_replace( - "/[^a-z0-9._-]+/i", - '', - $monarcObject->getName($anr->getLanguage()) . $isForMosp ? '_MOSP' : '' - ); - } -} diff --git a/src/Service/ObjectObjectService.php b/src/Service/ObjectObjectService.php deleted file mode 100644 index 757f6e87..00000000 --- a/src/Service/ObjectObjectService.php +++ /dev/null @@ -1,10 +0,0 @@ - Table\ObjectObjectTable::class, - 'entity' => ObjectObject::class, - 'anrTable' => Table\AnrTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'instanceTable' => Table\InstanceTable::class, - 'MonarcObjectTable' => Table\MonarcObjectTable::class, - 'childTable' => Table\MonarcObjectTable::class, - 'fatherTable' => Table\MonarcObjectTable::class, - ]; - - // TODO: A temporary solution to inject SharedEventManager. All the factories classes will be removed. - public function __invoke(ContainerInterface $container, $requestedName, array $options = null) - { - $objectObjectService = parent::__invoke($container, $requestedName, $options); - - $objectObjectService->setSharedManager($container->get('EventManager')->getSharedManager()); - - return $objectObjectService; - } -} diff --git a/src/Service/OperationalRiskScaleCommentService.php b/src/Service/OperationalRiskScaleCommentService.php index 98d8e8ba..23587f9f 100644 --- a/src/Service/OperationalRiskScaleCommentService.php +++ b/src/Service/OperationalRiskScaleCommentService.php @@ -1,26 +1,47 @@ operationalRiskScaleCommentTable = $operationalRiskScaleCommentTable; + $this->connectedUser = $connectedUserService->getConnectedUser(); + } + + public function update(Anr $anr, int $id, array $data): OperationalRiskScaleComment + { + /** @var OperationalRiskScaleComment $operationalRiskScaleComment */ + $operationalRiskScaleComment = $this->operationalRiskScaleCommentTable->findByIdAndAnr($id, $anr); + + if (isset($data['scaleValue'])) { + $operationalRiskScaleComment->setScaleValue((int)$data['scaleValue']); + } + if (isset($data['comment'])) { + $operationalRiskScaleComment->setComment($data['comment']); + } + $operationalRiskScaleComment->setUpdater($this->connectedUser->getEmail()); + + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment); + + return $operationalRiskScaleComment; } } diff --git a/src/Service/OperationalRiskScaleService.php b/src/Service/OperationalRiskScaleService.php index e6106b93..8e3067bf 100644 --- a/src/Service/OperationalRiskScaleService.php +++ b/src/Service/OperationalRiskScaleService.php @@ -1,123 +1,344 @@ connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getOperationalRiskScales(Entity\Anr $anr): array + { + $result = []; + + /** @var Entity\OperationalRiskScale $operationalRiskScale */ + foreach ($this->operationalRiskScaleTable->findByAnr($anr) as $operationalRiskScale) { + $comments = []; + /** @var Entity\OperationalRiskScaleComment $operationalRiskScaleComment */ + foreach ($operationalRiskScale->getOperationalRiskScaleComments() as $operationalRiskScaleComment) { + if (!$operationalRiskScaleComment->isHidden() + && $operationalRiskScaleComment->getOperationalRiskScaleType() === null + ) { + $comments[] = [ + 'id' => $operationalRiskScaleComment->getId(), + 'scaleId' => $operationalRiskScale->getId(), + 'scaleTypeId' => null, + 'scaleIndex' => $operationalRiskScaleComment->getScaleIndex(), + 'scaleValue' => $operationalRiskScaleComment->getScaleValue(), + 'comment' => $operationalRiskScaleComment->getComment(), + ]; + } + } + + $types = []; + /** @var Entity\OperationalRiskScaleType $operationalRiskScaleType */ + foreach ($operationalRiskScale->getOperationalRiskScaleTypes() as $operationalRiskScaleType) { + $commentsOfType = []; + /** @var Entity\OperationalRiskScaleComment $commentOfType */ + foreach ($operationalRiskScaleType->getOperationalRiskScaleComments() as $commentOfType) { + if (!$commentOfType->isHidden()) { + $commentsOfType[] = [ + 'id' => $commentOfType->getId(), + 'scaleId' => $operationalRiskScale->getId(), + 'scaleTypeId' => $operationalRiskScaleType->getId(), + 'scaleIndex' => $commentOfType->getScaleIndex(), + 'scaleValue' => $commentOfType->getScaleValue(), + 'comment' => $commentOfType->getComment(), + ]; + } + } + + $types[] = [ + 'id' => $operationalRiskScaleType->getId(), + 'scaleId' => $operationalRiskScale->getId(), + 'label' => $operationalRiskScaleType->getLabel(), + 'isHidden' => $operationalRiskScaleType->isHidden(), + 'comments' => $commentsOfType, + ]; + } + + $result[] = [ + 'id' => $operationalRiskScale->getId(), + 'max' => $operationalRiskScale->getMax(), + 'min' => $operationalRiskScale->getMin(), + 'type' => $operationalRiskScale->getType(), + 'comments' => $comments, + 'scaleTypes' => $types, + ]; + } + + return $result; + } + + public function createOperationalRiskScaleType(Entity\Anr $anr, array $data): Entity\OperationalRiskScaleType + { + /** @var Entity\OperationalRiskScale $operationalRiskScale */ + $operationalRiskScale = $this->operationalRiskScaleTable->findByAnrAndScaleId($anr, (int)$data['scaleId']); + + $operationalRiskScaleType = $this->getCreatedOperationalRiskScaleTypeObject($anr, $operationalRiskScale); + if (!empty($data['label'][$anr->getLanguageCode()])) { + $operationalRiskScaleType->setLabel($data['label'][$anr->getLanguageCode()]); + } + + // Process the scale comments. + if (!empty($data['comments'])) { + foreach ($data['comments'] as $scaleCommentData) { + $this->createScaleComment( + $anr, + $operationalRiskScale, + $operationalRiskScaleType, + $scaleCommentData['scaleIndex'], + $scaleCommentData['scaleValue'] + ); + } + } + + /* Link the new type with all the existed operational risks. */ + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + foreach ($this->instanceRiskOpTable->findByAnr($anr) as $operationalInstanceRisk) { + $this->instanceRiskOpService->createOperationalInstanceRiskScaleObject( + $operationalInstanceRisk, + $operationalRiskScaleType + ); + } + + $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType); + + return $operationalRiskScaleType; + } + + public function updateScaleType(Entity\Anr $anr, int $id, array $data): Entity\OperationalRiskScaleType + { + /** @var Entity\OperationalRiskScaleType $operationalRiskScaleType */ + $operationalRiskScaleType = $this->operationalRiskScaleTypeTable->findByIdAndAnr($id, $anr); + + $scaleTypeVisibilityBeforeUpdate = $operationalRiskScaleType->isHidden(); + if (isset($data['isHidden']) && $scaleTypeVisibilityBeforeUpdate !== (bool)$data['isHidden']) { + $this->anrScaleService->validateIfScalesAreEditable($anr); + + $operationalRiskScaleType->setIsHidden((bool)$data['isHidden']); + } + if (!empty($data['label'])) { + $operationalRiskScaleType->setLabel($data['label']); + } + + /* If the scale type visibility is changed, it's necessary to recalculate the total risk's values. */ + if ($scaleTypeVisibilityBeforeUpdate !== $operationalRiskScaleType->isHidden()) { + $updatedInstanceRiskIds = []; + foreach ($operationalRiskScaleType->getOperationalInstanceRiskScales() as $operationalInstanceRiskScale) { + /** @var Entity\InstanceRiskOp $operationalInstanceRisk */ + $operationalInstanceRisk = $operationalInstanceRiskScale->getOperationalInstanceRisk(); + if (!\in_array($operationalInstanceRisk->getId(), $updatedInstanceRiskIds, true)) { + $this->instanceRiskOpService->updateRiskCacheValues($operationalInstanceRisk); + $updatedInstanceRiskIds[] = $operationalInstanceRisk->getId(); + } + } + $this->operationalRiskScaleTypeTable->flush(); + } + + $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType); + + return $operationalRiskScaleType; + } + + public function deleteOperationalRiskScaleTypes(Entity\Anr $anr, array $data): void + { + $this->anrScaleService->validateIfScalesAreEditable($anr); + + foreach ($data as $id) { + /** @var Entity\OperationalRiskScaleType $scaleTypeToDelete */ + $scaleTypeToDelete = $this->operationalRiskScaleTypeTable->findByIdAndAnr((int)$id, $anr); + $this->operationalRiskScaleTable->remove($scaleTypeToDelete, false); + } + + $this->operationalRiskScaleTable->flush(); + } + + public function updateValueForAllScales(Entity\Anr $anr, array $data): void + { + $scaleIndex = (int)$data['scaleIndex']; + $scaleValue = (int)$data['scaleValue']; + + $operationalRiskScaleComments = $this->operationalRiskScaleCommentTable->findByAnrAndScaleTypeOrderByIndex( + $anr, + CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT ); + + foreach ($operationalRiskScaleComments as $operationalRiskScaleComment) { + if ($operationalRiskScaleComment->getScaleIndex() < $scaleIndex + && $operationalRiskScaleComment->getScaleValue() >= $scaleValue + ) { + $operationalRiskScaleComment->setScaleValue($scaleValue - 1); + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + } elseif ($operationalRiskScaleComment->getScaleIndex() > $scaleIndex + && $operationalRiskScaleComment->getScaleValue() <= $scaleValue + ) { + $operationalRiskScaleComment->setScaleValue($scaleValue + 1); + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + } elseif ($operationalRiskScaleComment->getScaleIndex() === $scaleIndex) { + $operationalRiskScaleComment->setScaleValue($scaleValue); + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + } + } + + $this->operationalRiskScaleCommentTable->flush(); } - protected function createOperationalRiskScaleTypeObject( - AnrSuperClass $anr, - OperationalRiskScaleSuperClass $operationalRiskScale - ): OperationalRiskScaleTypeSuperClass { - return (new OperationalRiskScaleType()) - ->setAnr($anr) - ->setOperationalRiskScale($operationalRiskScale) - ->setLabelTranslationKey((string)Uuid::uuid4()) - ->setCreator($this->connectedUser->getEmail()); + public function updateLevelsNumberOfOperationalRiskScale(Entity\Anr $anr, array $data) + { + // Change the levels number of the scale. + $levelsNumber = (int)$data['numberOfLevelForOperationalImpact']; + + /** @var Entity\OperationalRiskScale[] $operationalRiskScales */ + $operationalRiskScales = $this->operationalRiskScaleTable->findWithCommentsByAnrAndType( + $anr, + CoreEntity\OperationalRiskScaleSuperClass::TYPE_IMPACT + ); + + foreach ($operationalRiskScales as $operationalRiskScale) { + foreach ($operationalRiskScale->getOperationalRiskScaleTypes() as $operationalRiskScaleType) { + $operationalRiskScaleComments = $operationalRiskScaleType->getOperationalRiskScaleComments(); + + $maxScaleValue = 0; + foreach ($operationalRiskScaleComments as $operationalRiskScaleComment) { + if ($operationalRiskScaleComment->getScaleIndex() < $levelsNumber) { + $operationalRiskScaleComment->setIsHidden(false); + } else { + $operationalRiskScaleComment->setIsHidden(true); + if ($operationalRiskScaleComment->getScaleValue() <= $maxScaleValue) { + $operationalRiskScaleComment->setScaleValue(++$maxScaleValue); + } + } + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + if ($operationalRiskScaleComment->getScaleValue() > $maxScaleValue) { + $maxScaleValue = $operationalRiskScaleComment->getScaleValue(); + } + } + + // Set -1, because the range is counted from 0. + $operationalRiskScale->setMax($levelsNumber - 1); + + for ($index = $operationalRiskScale->getMin(); $index <= $operationalRiskScale->getMax(); $index++) { + if ($this->getCommentByIndex($index, $operationalRiskScaleComments) === null) { + $this->createScaleComment( + $anr, + $operationalRiskScale, + $operationalRiskScaleType, + $index, + ++$maxScaleValue, + ); + } + } + } + + $this->operationalRiskScaleTable->save($operationalRiskScale); + } } - protected function createTranslationObject( - AnrSuperClass $anr, - string $type, - string $key, - string $lang, - string $value - ): TranslationSuperClass { - return (new Translation()) + public function updateMinMaxForOperationalRiskProbability(Entity\Anr $anr, $data): void + { + $probabilityMin = (int)$data['probabilityMin']; + $probabilityMax = (int)$data['probabilityMax']; + + /** @var Entity\OperationalRiskScale[] $operationalRiskScales */ + $operationalRiskScales = $this->operationalRiskScaleTable->findWithCommentsByAnrAndType( + $anr, + CoreEntity\OperationalRiskScaleSuperClass::TYPE_LIKELIHOOD + ); + + foreach ($operationalRiskScales as $operationalRiskScale) { + $operationalRiskScaleComments = $operationalRiskScale->getOperationalRiskScaleComments(); + foreach ($operationalRiskScaleComments as $operationalRiskScaleComment) { + $scaleIndex = $operationalRiskScaleComment->getScaleIndex(); + if ($scaleIndex < $probabilityMin || $scaleIndex > $probabilityMax) { + $operationalRiskScaleComment->setIsHidden(true); + } else { + $operationalRiskScaleComment->setIsHidden(false); + } + $this->operationalRiskScaleCommentTable->save($operationalRiskScaleComment, false); + } + for ($index = $probabilityMin; $index <= $probabilityMax; $index++) { + if ($this->getCommentByIndex($index, $operationalRiskScaleComments) === null) { + $this->createScaleComment($anr, $operationalRiskScale, null, $index, $index); + } + } + + $operationalRiskScale->setMin($probabilityMin)->setMax($probabilityMax); + + $this->operationalRiskScaleTable->save($operationalRiskScale); + } + } + + protected function getCreatedOperationalRiskScaleTypeObject( + Entity\Anr $anr, + Entity\OperationalRiskScale $operationalRiskScale + ): Entity\OperationalRiskScaleType { + $operationalRiskScaleType = (new Entity\OperationalRiskScaleType()) ->setAnr($anr) - ->setType($type) - ->setKey($key) - ->setLang($lang) - ->setValue($value) + ->setOperationalRiskScale($operationalRiskScale) ->setCreator($this->connectedUser->getEmail()); + + $this->operationalRiskScaleTypeTable->save($operationalRiskScaleType, false); + + /** @var Entity\OperationalRiskScaleType */ + return $operationalRiskScaleType; } protected function createScaleComment( - AnrSuperClass $anr, - OperationalRiskScaleSuperClass $operationalRiskScale, - ?OperationalRiskScaleTypeSuperClass $operationalRiskScaleType, + Entity\Anr $anr, + Entity\OperationalRiskScale $operationalRiskScale, + ?Entity\OperationalRiskScaleType $operationalRiskScaleType, int $scaleIndex, - int $scaleValue, - array $languageCodes + int $scaleValue ): void { - $scaleComment = (new OperationalRiskScaleComment()) + $scaleComment = (new Entity\OperationalRiskScaleComment()) ->setAnr($anr) ->setOperationalRiskScale($operationalRiskScale) ->setScaleIndex($scaleIndex) ->setScaleValue($scaleValue) - ->setCommentTranslationKey((string)Uuid::uuid4()) ->setCreator($this->connectedUser->getEmail()); if ($operationalRiskScaleType !== null) { $scaleComment->setOperationalRiskScaleType($operationalRiskScaleType); } $this->operationalRiskScaleCommentTable->save($scaleComment, false); + } - foreach ($languageCodes as $languageCode) { - // Create a translation for the scaleComment (init with blank value). - $translation = $this->createTranslationObject( - $anr, - Translation::OPERATIONAL_RISK_SCALE_COMMENT, - $scaleComment->getCommentTranslationKey(), - $languageCode, - '' - ); - - $this->translationTable->save($translation, false); + /** + * @param int $index + * @param Entity\OperationalRiskScaleComment[] $operationalRiskScaleComments + */ + private function getCommentByIndex( + int $index, + iterable $operationalRiskScaleComments + ): ?Entity\OperationalRiskScaleComment { + foreach ($operationalRiskScaleComments as $operationalRiskScaleComment) { + if ($operationalRiskScaleComment->getScaleIndex() === $index) { + return $operationalRiskScaleComment; + } } - } - protected function getLanguageCodesForTranslations(AnrSuperClass $anr): array - { - return [$this->getAnrLanguageCode($anr)]; + return null; } } diff --git a/src/Service/SnapshotService.php b/src/Service/SnapshotService.php index 0ac46c80..44cafdd5 100755 --- a/src/Service/SnapshotService.php +++ b/src/Service/SnapshotService.php @@ -1,220 +1,133 @@ -connectedUser = $connectedUserService->getConnectedUser(); + } + + public function getList(Anr $anr): array { - if (is_null($order)) { - $order = '-id'; + $snapshotsList = []; + $snapshots = $this->snapshotTable->findByAnrReferenceAndOrderBy($anr, ['createdAt' => Criteria::DESC]); + foreach ($snapshots as $snapshot) { + $snapshotsList[] = [ + 'id' => $snapshot->getId(), + 'anr' => [ + 'id' => $snapshot->getAnr()->getId(), + ], + 'comment' => $snapshot->getComment(), + 'createdAt' => [ + 'date' => $snapshot->getCreatedAt()->format('Y-m-d H:i:s.u'), + ], + 'creator' => $snapshot->getCreator(), + ]; } - /** @var SnapshotTable $table */ - $table = $this->get('table'); - return $table->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd - ); + + return $snapshotsList; } - /** - * @throws ORMException - * @throws Exception - */ - public function create($data, $last = true): int + public function create(Anr $anr, array $data): Snapshot { - // duplicate anr and create snapshot record with new id - /** @var AnrService $anrService */ - $anrService = $this->get('anrService'); - $newAnr = $anrService->duplicateAnr($data['anr'], MonarcObject::SOURCE_CLIENT, null, [], true); - - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - /** @var SnapshotTable $snapshotTable */ - $snapshotTable = $this->get('table'); + $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). + */ + $newAnr->setIsVisibleOnDashboard(0)->setIsStatsCollected(0); + $this->anrTable->save($newAnr, false); - // TODO: Refactor this service and AnrService to be able to pass snapshot data in the constructor. $snapshot = (new Snapshot()) ->setAnr($newAnr) - ->setAnrReference($data['anr'] instanceof Anr ? $data['anr'] : $anrTable->findById($data['anr'])) - ->setCreator($newAnr->getCreator()) + ->setAnrReference($anr) + ->setCreator($this->connectedUser->getFirstname() . ' ' . $this->connectedUser->getLastname()) ->setComment($data['comment']); - $snapshotTable->saveEntity($snapshot); + $this->snapshotTable->save($snapshot); - // Snapshots should not be visible on global dashboard - // and stats not send to the StatsService (but snapshots are ignored anyway). - $newAnr->setIsVisibleOnDashboard(0) - ->setIsStatsCollected(0); - - $anrTable->saveEntity($newAnr); - - return $snapshot->getId(); + return $snapshot; } - /** - * @inheritdoc - */ - public function patch($id, $data) + public function delete(Anr $anr, int $id): void { - foreach ($data as $key => $value) { - if ($key !== 'comment') { - unset($data[$key]); - } - } - return parent::patch($id, $data); - } + /** @var Snapshot $snapshot */ + $snapshot = $this->snapshotTable->findByIdAndAnr($id, $anr); - /** - * @inheritdoc - */ - public function update($id, $data) - { - return $this->patch($id, $data); + $this->snapshotTable->remove($snapshot); } - /** - * @inheritdoc - */ - public function delete($id) + public function restore(Anr $anrReference, int $snapshotId): Anr { - /** @var SnapshotTable $snapshotTable */ - $snapshotTable = $this->get('table'); - $snapshot = $snapshotTable->getEntity($id); - - /** @var AnrService $anrService */ - $anrService = $this->get('anrService'); - - return $anrService->delete($snapshot->anr->id); - } - - /** - * @inheritdoc - */ - public function deleteInstanceRisk($id, $anrId = null) - { - // Ensure user is allowed to perform this action - if ($anrId !== null) { - $entity = $this->get('table')->getEntity($id); - if ($entity->anrReference->id !== $anrId) { - throw new Exception('Anr id error', 412); - } - - /** @var User $connectedUser */ - $connectedUser = $this->get('table')->getConnectedUser(); - - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $this->get('userAnrTable'); - $rights = $userAnrTable->getEntityByFields(['user' => $connectedUser->getId(), 'anr' => $anrId]); - $rwd = 0; - foreach ($rights as $right) { - if ($right->rwd == 1) { - $rwd = 1; - } - } - - if (!$rwd) { - throw new Exception('You are not authorized to do this action', 412); - } + /** @var Snapshot $snapshot */ + $snapshot = $this->snapshotTable->findById($snapshotId); + if ($snapshot->getAnrReference()->getId() !== $anrReference->getId()) { + throw new Exception('The analysis associated with the snapshot matches the requested one.', 412); } - return $this->delete($id); - } + /* Use the anr from the snapshot as a new one. */ + $snapshotAnr = $snapshot->getAnr(); - /** - * Restores a snapshot into a separate regular Anr. - * - * @param int $anrId Reference ANR ID - * @param int $id Snapshot ID to restore - * @return int Newly created ANR ID - */ - public function restore($anrId, $id) - { - // switch anr and anrReference - /** @var SnapshotTable $snapshotTable */ - $snapshotTable = $this->get('table'); - /** @var AnrService $anrService */ - $anrService = $this->get('anrService'); - /** @var AnrTable $anrTable */ - $anrTable = $this->get('anrTable'); - - $snapshot = $snapshotTable->findById($id); - /** @var Anr $anrReference */ - $anrReference = $snapshot->getAnrReference(); - - // duplicate the anr linked to this snapshot - $newAnr = $anrService->duplicateAnr($snapshot->getAnr(), MonarcObject::SOURCE_CLIENT, null, [], false, true); - - /** @var Snapshot[] $snapshots */ - $snapshots = $snapshotTable->getEntityByFields(['anrReference' => $anrId]); - //define new reference for all snapshots - foreach ($snapshots as $snap) { - $snap->setAnrReference($newAnr); - $snapshotTable->saveEntity($snap); + /* Update the reference for all the other snapshots. */ + foreach ($anrReference->getReferencedSnapshots() as $referencedSnapshot) { + if ($snapshot->getId() !== $referencedSnapshot->getId()) { + $this->snapshotTable->save($referencedSnapshot->setAnrReference($snapshotAnr), false); + } + $anrReference->removeReferencedSnapshot($referencedSnapshot); } - /** - * Transmit the to the new anr (restored from snapshot) access and settings from the replaced (old) anr. - */ - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $anrService->get('userAnrCliTable'); - $usersAnrs = $userAnrTable->findByAnrId($anrId); - - foreach ($usersAnrs as $userAnr) { - $userAnr->setAnr($newAnr); - $userAnrTable->saveEntity($userAnr); + /* Move permissions from the old anr to the new one. */ + foreach ($anrReference->getUsersAnrsPermissions() as $userAnrPermission) { + $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()) - ->setLabel1($anrReference->getLabel1()) - ->setLabel2($anrReference->getLabel2()) - ->setLabel3($anrReference->getLabel3()) - ->setLabel4($anrReference->getLabel4()); + ->setLabel($anrReference->getLabel()); $referenceAnrUuid = $anrReference->getUuid(); - $anrTable->deleteEntity($anrReference); - - $anrTable->saveEntity($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->getId(); + return $snapshotAnr; } } diff --git a/src/Service/SnapshotServiceFactory.php b/src/Service/SnapshotServiceFactory.php deleted file mode 100755 index c73404d1..00000000 --- a/src/Service/SnapshotServiceFactory.php +++ /dev/null @@ -1,25 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\Snapshot', - 'table' => 'Monarc\FrontOffice\Model\Table\SnapshotTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'anrService' => 'Monarc\FrontOffice\Service\AnrService', - ]; -} diff --git a/src/Service/SoaCategoryService.php b/src/Service/SoaCategoryService.php index 3f800e0c..96661b6b 100755 --- a/src/Service/SoaCategoryService.php +++ b/src/Service/SoaCategoryService.php @@ -1,98 +1,103 @@ -filterPatchFields($data); - parent::patch($id, $data); } - public function getList($page = 1, $limit = 25, $order = null, $filter = null, $filterAnd = null) + public function getList(FormattedInputParams $params): array { - [$filterJoin, $filterLeft, $filtersCol] = $this->get('entity')->getFiltersForService(); - - return $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd, - $filterJoin, - $filterLeft - ); + $result = []; + /** @var Entity\SoaCategory $soaCategory */ + foreach ($this->soaCategoryTable->findByParams($params) as $soaCategory) { + $result[] = $this->prepareSoaCategoryDataResult($soaCategory, true); + } + + return $result; } - public function delete($id) + public function getSoaCategoryData(Entity\Anr $anr, int $id): array { - $table = $this->get('table'); - $categ = $table->getEntity($id); - foreach ($categ->measures as $measure) { - $measure->setCategory(null); - } + /** @var Entity\SoaCategory $soaCategory */ + $soaCategory = $this->soaCategoryTable->findByIdAndAnr($id, $anr); - return parent::delete($id); + return $this->prepareSoaCategoryDataResult($soaCategory); } - public function getOrCreateSoaCategory( - ImportCacheHelper $importCacheHelper, - Anr $anr, - Referential $referential, - string $labelValue - ): SoaCategory { - $languageIndex = $anr->getLanguage(); - $labelKey = 'label' . $languageIndex; - - $importCacheHelper->prepareSoaCategoriesCacheData($anr); - - $cacheKey = $referential->getUuid() . '_' . $labelValue; - $soaCategory = $importCacheHelper->getItemFromArrayCache('soa_categories_by_ref_and_label', $cacheKey); - if ($soaCategory !== null) { - return $soaCategory; + public function create(Entity\Anr $anr, array $data, bool $saveInDb = true): Entity\SoaCategory + { + /** @var Entity\Referential $referential */ + $referential = $data['referential'] instanceof Entity\Referential + ? $data['referential'] + : $this->referentialTable->findByUuidAndAnr($data['referential'], $anr); + + /** @var Entity\SoaCategory $soaCategory */ + $soaCategory = (new Entity\SoaCategory())->setAnr($anr)->setLabels($data)->setReferential($referential); + + $this->soaCategoryTable->save($soaCategory, $saveInDb); + + return $soaCategory; + } + + public function createList(Entity\Anr $anr, array $data): array + { + $createdCategories = []; + foreach ($data as $datum) { + $createdCategories[] = $this->create($anr, $datum, false); } + $this->soaCategoryTable->flush(); - $soaCategory = (new SoaCategory()) - ->setAnr($anr) - ->setReferential($referential) - ->setLabels([$labelKey => $labelValue]); + $createdIds = []; + foreach ($createdCategories as $category) { + $createdIds[] = $category->getId(); + } + + return $createdIds; + } - /** @var SoaCategoryTable $soaCategoryTable */ - $soaCategoryTable = $this->get('table'); - $soaCategoryTable->saveEntity($soaCategory, false); + public function update(Entity\Anr $anr, int $id, array $data): Entity\SoaCategory + { + /** @var Entity\SoaCategory $soaCategory */ + $soaCategory = $this->soaCategoryTable->findByIdAndAnr($id, $anr); - $importCacheHelper->addItemToArrayCache('soa_categories_by_ref_and_label', $soaCategory, $cacheKey); + $this->soaCategoryTable->save($soaCategory->setLabels($data)); return $soaCategory; } + + public function delete(Entity\Anr $anr, int $id): void + { + /** @var Entity\SoaCategory $soaCategory */ + $soaCategory = $this->soaCategoryTable->findByIdAndAnr($id, $anr); + + $this->soaCategoryTable->remove($soaCategory); + } + + private function prepareSoaCategoryDataResult( + Entity\SoaCategory $soaCategory, + bool $includeReferential = false + ): array { + $result = array_merge(['id' => $soaCategory->getId()], $soaCategory->getLabels()); + if ($includeReferential) { + $result['referential'] = array_merge( + ['uuid' => $soaCategory->getReferential()->getUuid()], + $soaCategory->getReferential()->getLabels() + ); + } + + return $result; + } } diff --git a/src/Service/SoaCategoryServiceFactory.php b/src/Service/SoaCategoryServiceFactory.php deleted file mode 100755 index f2d27adf..00000000 --- a/src/Service/SoaCategoryServiceFactory.php +++ /dev/null @@ -1,24 +0,0 @@ - 'Monarc\FrontOffice\Model\Entity\SoaCategory', - 'table' => 'Monarc\FrontOffice\Model\Table\SoaCategoryTable', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userAnrTable' => 'Monarc\FrontOffice\Model\Table\UserAnrTable', - ]; -} diff --git a/src/Service/SoaScaleCommentService.php b/src/Service/SoaScaleCommentService.php index 422b7a54..3ee03681 100644 --- a/src/Service/SoaScaleCommentService.php +++ b/src/Service/SoaScaleCommentService.php @@ -1,90 +1,107 @@ anrTable = $anrTable; - $this->connectedUser = $connectedUserService->getConnectedUser(); + private SoaScaleCommentTable $soaScaleCommentTable; + + private UserSuperClass $connectedUser; + + public function __construct(SoaScaleCommentTable $soaScaleCommentTable, ConnectedUserService $connectedUserService) + { $this->soaScaleCommentTable = $soaScaleCommentTable; - $this->translationTable = $translationTable; - $this->configService = $configService; + $this->connectedUser = $connectedUserService->getConnectedUser(); } - protected function createSoaScaleComment( - AnrSuperClass $anr, - int $scaleIndex, - array $languageCodes, - bool $isFlushable = false - ): void { - $scaleComment = (new soaScaleComment()) - ->setAnr($anr) - ->setScaleIndex($scaleIndex) - ->setColour('') - ->setIsHidden(false) - ->setCommentTranslationKey((string)Uuid::uuid4()) - ->setCreator($this->connectedUser->getEmail()); + public function getSoaScaleCommentsData(Anr $anr): array + { + $result = []; + /** @var SoaScaleComment[] $soaScaleComments */ + $soaScaleComments = $this->soaScaleCommentTable->findByAnrOrderByIndex($anr); + foreach ($soaScaleComments as $soaScaleComment) { + $result[] = $this->getPreparedSoaScaleCommentData($soaScaleComment); + } - $this->soaScaleCommentTable->save($scaleComment, false); + return $result; + } - foreach ($languageCodes as $languageCode) { - // Create a translation for the scaleComment (init with blank value). - $translation = $this->createTranslationObject( - $anr, - Translation::SOA_SCALE_COMMENT, - $scaleComment->getCommentTranslationKey(), - $languageCode, - '' - ); + public function getPreparedSoaScaleCommentData(SoaScaleComment $soaScaleComment): array + { + return [ + 'id' => $soaScaleComment->getId(), + 'scaleIndex' => $soaScaleComment->getScaleIndex(), + 'colour' => $soaScaleComment->getColour(), + 'comment' => $soaScaleComment->getComment(), + 'isHidden' => $soaScaleComment->isHidden(), + ]; + } - $this->translationTable->save($translation, false); - } + public function createOrHideSoaScaleComments(Anr $anr, array $data): void + { + $soaScaleComments = $this->soaScaleCommentTable->findByAnrOrderByIndex($anr); + + if (isset($data['numberOfLevels'])) { + $levelsNumber = (int)$data['numberOfLevels']; + foreach ($soaScaleComments as $soaScaleComment) { + $soaScaleComment + ->setIsHidden($soaScaleComment->getScaleIndex() >= $levelsNumber) + ->setUpdater($this->connectedUser->getEmail()); + $this->soaScaleCommentTable->save($soaScaleComment, false); + } + $numberOfCurrentComments = \count($soaScaleComments); + if ($levelsNumber > $numberOfCurrentComments) { + for ($i = $numberOfCurrentComments; $i < $levelsNumber; $i++) { + $this->createSoaScaleComment($anr, $i); + } + } - if ($isFlushable) { $this->soaScaleCommentTable->flush(); } } - protected function createTranslationObject( - AnrSuperClass $anr, - string $type, - string $key, - string $lang, - string $value - ): TranslationSuperClass { - return (new Translation()) + public function update(Anr $anr, int $id, array $data): void + { + /** @var SoaScaleComment $soaScaleComment */ + $soaScaleComment = $this->soaScaleCommentTable->findByIdAndAnr($id, $anr); + + if (isset($data['comment'])) { + $soaScaleComment->setComment($data['comment']); + } + if (!empty($data['colour'])) { + $soaScaleComment->setColour($data['colour']); + } + + $this->soaScaleCommentTable->save($soaScaleComment->setUpdater($this->connectedUser->getEmail())); + } + + public function createSoaScaleComment( + Anr $anr, + int $scaleIndex, + string $colour = '', + string $comment = '', + bool $isHidden = false + ): SoaScaleComment { + $soaScaleComment = (new SoaScaleComment()) ->setAnr($anr) - ->setType($type) - ->setKey($key) - ->setLang($lang) - ->setValue($value) + ->setScaleIndex($scaleIndex) + ->setColour($colour) + ->setComment($comment) + ->setIsHidden($isHidden) ->setCreator($this->connectedUser->getEmail()); + $this->soaScaleCommentTable->save($soaScaleComment, false); + + return $soaScaleComment; } } diff --git a/src/Service/SoaService.php b/src/Service/SoaService.php index 03e0c5a5..4513734a 100755 --- a/src/Service/SoaService.php +++ b/src/Service/SoaService.php @@ -1,84 +1,156 @@ -get('entity')->getFiltersForService(); - - $data = $this->get('table')->fetchAllFiltered( - array_keys($this->get('entity')->getJsonArray()), - $page, - 0, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $filtersCol), - $filterAnd, - $filterJoin, - $filterLeft - ); - if ($order == "m.code" || $order == "-m.code") { - $desc = ($order == "-m.code"); - if (!$desc) { - uasort($data, function ($a, $b) { - return strnatcmp($a['measure']->get('code'), $b['measure']->get('code')); - }); - } else { - uasort($data, function ($a, $b) { - return strnatcmp($b['measure']->get('code'), $a['measure']->get('code')); - }); + $result = []; + /** @var Entity\Soa $soa */ + foreach ($this->soaTable->findByParams($params) as $soa) { + $measure = $soa->getMeasure(); + $linkedMeasuresUuids = []; + foreach ($measure->getLinkedMeasures() as $linkedMeasure) { + $linkedMeasuresUuids[] = $linkedMeasure->getUuid(); } + $amvsData = []; + $amvsUuids = []; + foreach ($measure->getAmvs() as $amv) { + $amvsUuids[] = $amv->getUuid(); + } + if (!empty($amvsUuids)) { + $amvsData = $this->anrInstanceRiskService->getInstanceRisks($soa->getAnr(), null, [ + 'amvs' => $amvsUuids, + 'limit' => -1, + 'order' => 'maxRisk', + 'order_direction' => 'desc', + ]); + } + $rolfRisksData = []; + $rolfRisksIds = []; + foreach ($measure->getRolfRisks() as $rolfRisk) { + $rolfRisksIds[] = $rolfRisk->getId(); + } + if (!empty($amvsUuids)) { + $rolfRisksData = $this->anrInstanceRiskOpService->getOperationalRisks($measure->getAnr(), null, [ + 'rolfRisks' => $rolfRisksIds, + 'limit' => -1, + 'order' => 'cacheNetRisk', + 'order_direction' => 'desc', + ]); + } + + $result[] = [ + 'id' => $soa->getId(), + 'remarks' => $soa->getRemarks(), + 'evidences' => $soa->getEvidences(), + 'actions' => $soa->getActions(), + 'compliance' => $soa->getCompliance(), + 'EX' => $soa->getEx(), + 'LR' => $soa->getLr(), + 'CO' => $soa->getCo(), + 'BR' => $soa->getBr(), + 'BP' => $soa->getBp(), + 'RRA' => $soa->getRra(), + 'soaScaleComment' => $soa->getSoaScaleComment() === null ? null : [ + 'id' => $soa->getSoaScaleComment()->getId(), + 'colour' => $soa->getSoaScaleComment()->getColour(), + 'comment' => $soa->getSoaScaleComment()->getComment(), + 'scaleIndex' => $soa->getSoaScaleComment()->getScaleIndex(), + 'isHidden' => $soa->getSoaScaleComment()->isHidden(), + ], + 'measure' => array_merge([ + 'id' => $measure->getId(), + 'uuid' => $measure->getUuid(), + 'referential' => array_merge([ + 'uuid' => $measure->getReferential()->getUuid(), + ], $measure->getReferential()->getLabels()), + 'code' => $measure->getCode(), + 'category' => $measure->getCategory() === null + ? [] + : array_merge(['id' => $measure->getCategory()->getId()], $measure->getCategory()->getLabels()), + 'status' => $measure->getStatus(), + 'linkedMeasures' => $linkedMeasuresUuids, + 'amvs' => $amvsData, + 'rolfRisks' => $rolfRisksData, + ], $measure->getLabels()) + ]; } - if ($limit != 0) { - return array_slice($data, ($page - 1) * $limit, $limit, false); - } - return $data; + return $result; + } + + public function getCount(FormattedInputParams $params): int + { + return $this->soaTable->countByParams($params); + } + + public function createSoaObject(Entity\Anr $anr, Entity\Measure $measure, array $data = []): Entity\Soa + { + $soa = (new Entity\Soa())->setAnr($anr)->setMeasure($measure); + $this->setSoaData($anr, $soa, $data); + + $this->soaTable->save($soa, false); + + return $soa; + } + + public function patchSoa(Entity\Anr $anr, int $id, array $data, bool $saveInDb = true): Entity\Soa + { + /** @var Entity\Soa $soa */ + $soa = $this->soaTable->findByIdAndAnr($id, $anr); + + return $this->patchSoaObject($anr, $soa, $data, $saveInDb); + } + + public function patchSoaObject(Entity\Anr $anr, Entity\Soa $soa, array $data, bool $saveInDb = true): Entity\Soa + { + $this->setSoaData($anr, $soa, $data); + + $this->soaTable->save($soa, $saveInDb); + + return $soa; } /** - * @inheritdoc + * @return int[] */ - public function getFilteredCount($filter = null, $filterAnd = null) + public function patchList(Entity\Anr $anr, array $data): array { - list($filterJoin, $filterLeft, $filtersCol) = $this->get('entity')->getFiltersForService(); - - return $this->get('table')->countFiltered( - $this->parseFrontendFilter($filter, $filtersCol), - $filterAnd, - $filterJoin, - $filterLeft - ); + $updatedIds = []; + foreach ($data as $row) { + $id = $row['id']; + if (\is_array($row['soaScaleComment'])) { + $row['soaScaleComment'] = $row['soaScaleComment']['id']; + } + $updatedIds[] = $this->patchSoa($anr, $id, $row, false)->getId(); + } + $this->soaTable->flush(); + + return $updatedIds; } - public function patchSoa(int $id, array $data) + private function setSoaData(Entity\Anr $anr, Entity\Soa $soa, array $data): void { - $table = $this->get('table'); - $soa = $table->findById($id); if (isset($data['remarks'])) { $soa->setRemarks($data['remarks']); } @@ -106,11 +178,12 @@ public function patchSoa(int $id, array $data) if (isset($data['RRA'])) { $soa->setRra($data['RRA']); } - if (isset($data['soaScaleComment'])) { - $soaScaleCommentTable = $this->get('soaScaleCommentTable'); - $soaScaleComment = $soaScaleCommentTable->findById($data['soaScaleComment']); - $soa->setSoaScaleComment($soaScaleComment); + if (!empty($data['soaScaleComment'])) { + /** @var Entity\SoaScaleComment $newSoaScaleComment */ + $newSoaScaleComment = $data['soaScaleComment'] instanceof Entity\SoaScaleComment + ? $data['soaScaleComment'] + : $this->soaScaleCommentTable->findByIdAndAnr((int)$data['soaScaleComment'], $anr); + $soa->setSoaScaleComment($newSoaScaleComment); } - $table->saveEntity($soa); } } diff --git a/src/Service/SoaServiceFactory.php b/src/Service/SoaServiceFactory.php deleted file mode 100755 index d05fea24..00000000 --- a/src/Service/SoaServiceFactory.php +++ /dev/null @@ -1,30 +0,0 @@ - Soa::class, - 'table' => Table\SoaTable::class, - 'anrTable' => Table\AnrTable::class, - 'userAnrTable' => Table\UserAnrTable::class, - 'soaScaleCommentTable' => Table\SoaScaleCommentTable::class, - ]; -} diff --git a/src/Service/SystemMessageService.php b/src/Service/SystemMessageService.php new file mode 100644 index 00000000..89b854db --- /dev/null +++ b/src/Service/SystemMessageService.php @@ -0,0 +1,51 @@ +getConnectedUser(); + $this->connectedUser = $connectedUser; + } + + public function getListOfActiveMessages(): array + { + $result = []; + foreach ($this->systemMessageTable->findAllActiveByUser($this->connectedUser) as $systemMessage) { + $result[] = [ + 'id' => $systemMessage->getId(), + 'title' => $systemMessage->getTitle(), + 'description' => $systemMessage->getDescription(), + ]; + } + + return $result; + } + + public function inactivateMessage(int $id): void + { + $systemMessage = $this->systemMessageTable->findByIdAndUser($id, $this->connectedUser); + if ($systemMessage->getStatus() === SystemMessage::STATUS_ACTIVE) { + $this->systemMessageTable->save( + $systemMessage->setStatus(SystemMessage::STATUS_INACTIVE)->setUpdater($this->connectedUser->getEmail()) + ); + } + } +} diff --git a/src/Service/Traits/RecommendationsPositionsUpdateTrait.php b/src/Service/Traits/RecommendationsPositionsUpdateTrait.php index fdacb984..c62c514c 100644 --- a/src/Service/Traits/RecommendationsPositionsUpdateTrait.php +++ b/src/Service/Traits/RecommendationsPositionsUpdateTrait.php @@ -1,14 +1,18 @@ -getRecommendationRisks(); if ($recommendationRisks === null) { @@ -27,7 +31,7 @@ public function updateInstanceRiskRecommendationsPositions($instanceRisk): void $riskRecommendations = []; if ($instanceRisk->isTreated()) { foreach ($recommendationRisks as $recommendationRisk) { - $recommendation = $recommendationRisk->getRecommandation(); + $recommendation = $recommendationRisk->getRecommendation(); if ($recommendation->isImportanceEmpty() || !$recommendation->isPositionEmpty()) { continue; } @@ -42,7 +46,7 @@ public function updateInstanceRiskRecommendationsPositions($instanceRisk): void } } else { foreach ($recommendationRisks as $recommendationRisk) { - $recommendation = $recommendationRisk->getRecommandation(); + $recommendation = $recommendationRisk->getRecommendation(); if ($recommendation->isPositionEmpty() || $recommendation->isImportanceEmpty() || \count($recommendation->getRecommendationRisks()) > 1 @@ -65,8 +69,6 @@ public function updateInstanceRiskRecommendationsPositions($instanceRisk): void * Resets positions of the recommendations related to the informational/operational risk if not linked anymore. * * @param InstanceRisk|InstanceRiskOp $instanceRisk - * - * @throws OptimisticLockException */ protected function processRemovedInstanceRiskRecommendationsPositions($instanceRisk): void { @@ -76,7 +78,7 @@ protected function processRemovedInstanceRiskRecommendationsPositions($instanceR ) { $recommendationsToResetPositions = []; foreach ($instanceRisk->getRecommendationRisks() as $recommendationRisk) { - $linkedRecommendation = $recommendationRisk->getRecommandation(); + $linkedRecommendation = $recommendationRisk->getRecommendation(); if (!$linkedRecommendation->hasLinkedRecommendationRisks()) { $recommendationsToResetPositions[$linkedRecommendation->getUuid()] = $linkedRecommendation; } @@ -91,8 +93,6 @@ protected function processRemovedInstanceRiskRecommendationsPositions($instanceR * @param AnrSuperClass $anr * @param array $riskRecommendations List of recommendations to reset the positions (set ot 0), * Keys of the array are UUIDs, values are Recommendation objects. - * - * @throws OptimisticLockException */ protected function resetRecommendationsPositions(AnrSuperClass $anr, array $riskRecommendations): void { @@ -105,23 +105,23 @@ protected function resetRecommendationsPositions(AnrSuperClass $anr, array $risk ); $positionShiftAdjustment = 0; - /** @var Recommandation[] $riskRecommendations */ + /** @var Recommendation[] $riskRecommendations */ foreach ($riskRecommendations as $riskRecommendation) { foreach ($linkedRecommendations as $linkedRecommendation) { if ($linkedRecommendation->isPositionLowerThan( $riskRecommendation->getPosition() + $positionShiftAdjustment )) { $linkedRecommendation->shiftPositionUp(); - $recommendationTable->saveEntity($riskRecommendation, false); + $recommendationTable->save($riskRecommendation, false); } } $positionShiftAdjustment--; $riskRecommendation->setEmptyPosition(); - $recommendationTable->saveEntity($riskRecommendation, false); + $recommendationTable->save($riskRecommendation, false); } - $recommendationTable->getDb()->flush(); + $recommendationTable->flush(); } private function updateRecommendationsPositions(AnrSuperClass $anr, array $riskRecommendations): void @@ -136,16 +136,16 @@ private function updateRecommendationsPositions(AnrSuperClass $anr, array $riskR $maxPositionsPerImportance = $this->getMaxPositionsPerImportance($linkedRecommendations); - /** @var Recommandation[] $riskRecommendations */ + /** @var Recommendation[] $riskRecommendations */ if ($this->isImportanceOrderRespected($linkedRecommendations)) { foreach ($riskRecommendations as $riskRecommendation) { $riskRecommendation->setPosition(++$maxPositionsPerImportance[$riskRecommendation->getImportance()]); - $recommendationTable->saveEntity($riskRecommendation, false); + $recommendationTable->save($riskRecommendation, false); foreach ($linkedRecommendations as $linkedRecommendation) { if ($linkedRecommendation->isImportanceLowerThan($riskRecommendation->getImportance())) { $linkedRecommendation->shiftPositionDown(); - $recommendationTable->saveEntity($linkedRecommendation, false); + $recommendationTable->save($linkedRecommendation, false); } } @@ -158,22 +158,22 @@ private function updateRecommendationsPositions(AnrSuperClass $anr, array $riskR $maxPosition = max($maxPositionsPerImportance); foreach ($riskRecommendations as $riskRecommendation) { $riskRecommendation->setPosition(++$maxPosition); - $recommendationTable->saveEntity($riskRecommendation, false); + $recommendationTable->save($riskRecommendation, false); } } - $recommendationTable->getDb()->flush(); + $recommendationTable->flush(); } /** - * @param Recommandation[] $linkedRecommendations + * @param Recommendation[] $linkedRecommendations */ private function getMaxPositionsPerImportance(array $linkedRecommendations): array { $maxPositionsPerImportance = [ - Recommandation::HIGH_IMPORTANCE => 0, - Recommandation::MEDIUM_IMPORTANCE => 0, - Recommandation::LOW_IMPORTANCE => 0, + Recommendation::HIGH_IMPORTANCE => 0, + Recommendation::MEDIUM_IMPORTANCE => 0, + Recommendation::LOW_IMPORTANCE => 0, ]; foreach ($linkedRecommendations as $linkedRecommendation) { $maxPositionsPerImportance[$linkedRecommendation->getImportance()] = $linkedRecommendation->getPosition(); @@ -212,11 +212,11 @@ private function increaseMaxPositionsForLowerImportance(array $maxPositionsPerIm } /** - * @param Recommandation[] $linkedRecommendations + * @param Recommendation[] $linkedRecommendations */ private function isImportanceOrderRespected(array $linkedRecommendations): bool { - $previousRecommendationImportance = Recommandation::HIGH_IMPORTANCE; + $previousRecommendationImportance = Recommendation::HIGH_IMPORTANCE; foreach ($linkedRecommendations as $linkedRecommendation) { if ($linkedRecommendation->isImportanceHigherThan($previousRecommendationImportance)) { return false; @@ -227,10 +227,7 @@ private function isImportanceOrderRespected(array $linkedRecommendations): bool return true; } - /** - * TODO: remove the method when all the services, that use the trait will use dependencies' injection via constructor. - */ - private function getRecommendationTable(): RecommandationTable + private function getRecommendationTable(): RecommendationTable { if (property_exists(\get_class($this), 'recommendationTable')) { return $this->recommendationTable; diff --git a/src/Service/UserAnrService.php b/src/Service/UserAnrService.php deleted file mode 100755 index ce31a874..00000000 --- a/src/Service/UserAnrService.php +++ /dev/null @@ -1,120 +0,0 @@ -anr permissions matrix. This is a simple CRUD service. - * @package Monarc\FrontOffice\Service - */ -class UserAnrService extends AbstractService -{ - protected $anrTable; - protected $userTable; - protected $dependencies = ['anr', 'user']; - - /** - * Retrieves the user <-> ANR permissions matrix - * @return array An array with the rights for each user - */ - public function getMatrix() - { - //retieve matrix of rights (users and anrs) - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $this->get('table'); - $usersAnrs = $userAnrTable->fetchAllObject(); - - $rights = []; - foreach ($usersAnrs as $userAnr) { - $rights[] = [ - 'id' => $userAnr->id, - 'userId' => $userAnr->user->id, - 'firstname' => $userAnr->user->firstname, - 'lastname' => $userAnr->user->lastname, - 'email' => $userAnr->user->email, - 'anrId' => $userAnr->anr->id, - 'label1' => $userAnr->anr->label1, - 'label2' => $userAnr->anr->label2, - 'label3' => $userAnr->anr->label3, - 'label4' => $userAnr->anr->label4, - 'rwd' => $userAnr->rwd, - ]; - } - - return $rights; - } - - - /** - * @inheritdoc - */ - public function create($data, $last = true) - { - //verify if this right not already exist - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $this->get('table'); - $userAnr = $userAnrTable->getEntityByFields(['user' => $data['user'], 'anr' => $data['anr']]); - if (count($userAnr)) { - throw new \Monarc\Core\Exception\Exception('This right already exist', 412); - } - - return parent::create($data, $last); - } - - /** - * @inheritdoc - */ - public function getEntity($id) - { - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $this->get('table'); - $userAnr = $userAnrTable->get($id); - - return [ - 'id' => $userAnr['id'], - 'userId' => $userAnr['user']->id, - 'firstname' => $userAnr['user']->firstname, - 'lastname' => $userAnr['user']->lastname, - 'email' => $userAnr['user']->email, - 'anrId' => $userAnr['anr']->id, - 'label1' => $userAnr['anr']->label1, - 'label2' => $userAnr['anr']->label2, - 'label3' => $userAnr['anr']->label3, - 'label4' => $userAnr['anr']->label4, - 'rwd' => $userAnr['rwd'], - ]; - } - - /** - * @inheritdoc - */ - public function patch($id, $data) - { - // Check if the permission already exists to avoid duplicates - /** @var UserAnrTable $userAnrTable */ - $userAnrTable = $this->get('table'); - $userAnr = $userAnrTable->get($id); - if ( - ((isset($data['user'])) && ($data['user'] != $userAnr['user']->id)) - || - ((isset($data['anr'])) && ($data['anr'] != $userAnr['anr']->id)) - ) { - $newUser = (isset($data['user'])) ? $data['user'] : $userAnr['user']->id; - $newAnr = (isset($data['anr'])) ? $data['anr'] : $userAnr['anr']->id; - - $existingUserAnr = $userAnrTable->getEntityByFields(['user' => $newUser, 'anr' => $newAnr]); - if (count($existingUserAnr)) { - throw new \Monarc\Core\Exception\Exception('This right already exist', 412); - } - } - - parent::patch($id, $data); - } -} diff --git a/src/Service/UserAnrServiceFactory.php b/src/Service/UserAnrServiceFactory.php deleted file mode 100755 index 6bd0d19a..00000000 --- a/src/Service/UserAnrServiceFactory.php +++ /dev/null @@ -1,24 +0,0 @@ - 'Monarc\FrontOffice\Model\Table\UserAnrTable', - 'entity' => 'Monarc\FrontOffice\Model\Entity\UserAnr', - 'anrTable' => 'Monarc\FrontOffice\Model\Table\AnrTable', - 'userTable' => 'Monarc\FrontOffice\Model\Table\UserTable', - ]; -} diff --git a/src/Service/UserRoleService.php b/src/Service/UserRoleService.php index 404569a7..d5041be4 100755 --- a/src/Service/UserRoleService.php +++ b/src/Service/UserRoleService.php @@ -1,60 +1,46 @@ -userAnrTable = $userAnrTable; + parent::__construct($userTable, $userTokenTable); } - /** - * Retrieve user's roles from its authentication token - * @param string $token User authentication token - * @return array An array of roles and ANRs accesses - * @throws \Exception If the token is not found - */ - public function getByUserToken($token) + public function getUserRolesByToken(string $token): array { - // Retrieve user access - $userId = $this->getUserIdByToken($token); - $anrs = []; - $userAnrs = $this->userAnrTable->getEntityByFields(['user' => $userId]); - foreach ($userAnrs as $userAnr) { - $anrs[] = [ - 'anr' => $userAnr->anr->id, - 'rwd' => $userAnr->rwd + $userToken = $this->userTokenTable->findByToken($token); + if ($userToken === null) { + throw new UserNotLoggedInException(); + } + + $userAnrs = []; + /** @var UserAnr $userAnr */ + foreach ($userToken->getUser()->getUserAnrs() as $userAnr) { + $userAnrs[] = [ + 'anr' => $userAnr->getAnr()->getId(), + 'rwd' => $userAnr->getRwd(), ]; } return [ - 'roles' => $this->getByUserId($userId), - 'anrs' => $anrs + 'roles' => parent::getUserRolesByToken($token), + 'anrs' => $userAnrs, ]; } } diff --git a/src/Service/UserService.php b/src/Service/UserService.php index 61e9994c..9a0dcfa4 100755 --- a/src/Service/UserService.php +++ b/src/Service/UserService.php @@ -1,93 +1,34 @@ -anrTable = $anrTable; - $this->connectedUserService = $connectedUserService; - $this->passwordService = $passwordService; - } - - // TODO: remove me. - protected function filterGetFields(&$entity, $forbiddenFields = []) - { - if (empty($forbiddenFields)) { - $forbiddenFields = $this->forbiddenFields; - } - - foreach ($entity as $id => $user) { - foreach ($entity[$id] as $key => $value) { - if (in_array($key, $forbiddenFields)) { - unset($entity[$id][$key]); - } - } - } - } - - /** - * @inheritdoc - */ - public function getList($page = 1, $limit = 25, $order = null, $filter = null, $filterAnd = null) - { - $users = $this->userTable->fetchAllFiltered( - ['id', 'status', 'firstname', 'lastname', 'email', 'language', 'roles'], - $page, - $limit, - $this->parseFrontendOrder($order), - $this->parseFrontendFilter($filter, $this->filterColumns), - $filterAnd - ); - - $this->filterGetFields($users); - - return $users; + parent::__construct($userTable, $connectedUserService, $config); } public function getCompleteUser(int $userId): array @@ -95,7 +36,6 @@ public function getCompleteUser(int $userId): array /** @var User $user */ $user = $this->userTable->findById($userId); - // TODO: replace with normalization layer. return [ 'id' => $user->getId(), 'status' => $user->getStatus(), @@ -103,38 +43,32 @@ public function getCompleteUser(int $userId): array 'lastname' => $user->getLastname(), 'email' => $user->getEmail(), 'language' => $user->getLanguage(), - 'role' => $user->getRoles(), + 'role' => $user->getRolesArray(), 'anrs' => $this->anrTable->fetchAnrsExcludeSnapshotsWithUserRights($userId), ]; } - - /** - * @inheritdoc - */ public function create(array $data): UserSuperClass { if (empty($data['language'])) { $data['language'] = $this->defaultLanguageIndex; } if (empty($data['creator'])) { - $data['creator'] = $this->userTable->getConnectedUser()->getFirstname() . ' ' - . $this->userTable->getConnectedUser()->getLastname(); + $data['creator'] = $this->connectedUser->getEmail(); } - if (isset($data['anrs'])) { - foreach ($data['anrs'] as $anr) { - $anrEntity = $this->anrTable->findById($anr['id']); + foreach ($data['anrs'] ?? [] as $anr) { + /** @var Anr $anrEntity */ + $anrEntity = $this->anrTable->findById((int)$anr['id']); - $data['userAnrs'][] = (new UserAnr()) - ->setAnr($anrEntity) - ->setRwd($anr['rwd']) - ->setCreator($data['creator']); - } + $data['userAnrs'][] = (new UserAnr()) + ->setAnr($anrEntity) + ->setRwd($anr['rwd']) + ->setCreator($data['creator']); } $user = new User($data); - $this->userTable->saveEntity($user); + $this->userTable->save($user); return $user; } @@ -148,23 +82,12 @@ public function update(int $userId, array $data): UserSuperClass $this->updateUserAnr($user, $data); - if (isset($data['dateEnd'])) { - $data['dateEnd'] = new DateTime($data['dateEnd']); - } - - if (isset($data['dateStart'])) { - $data['dateStart'] = new DateTime($data['dateStart']); - } - - $this->userTable->saveEntity($user); + $this->userTable->save($user); return $user; } - /** - * @inheritdoc - */ - public function patch($userId, $data): UserSuperClass + public function patch(int $userId, array $data): UserSuperClass { if (isset($data['password'])) { $this->passwordService->changePasswordWithoutOldPassword($data['id'], $data['password']); @@ -181,33 +104,22 @@ public function patch($userId, $data): UserSuperClass $this->updateUserAnr($user, $data); - if (isset($data['dateEnd'])) { - $data['dateEnd'] = new DateTime($data['dateEnd']); - } - - if (isset($data['dateStart'])) { - $data['dateStart'] = new DateTime($data['dateStart']); - } - - $this->userTable->saveEntity($user); + $this->userTable->save($user); return $user; } /** - * Checks whether or not a specific action is authorized or not for the specified user id + * Checks whether a specific action is authorized or not for the specified user id. */ private function verifySystemUserUpdate(User $user, array $data = []) { - /* - * We just need to validate if the System created user instead. - */ if ($user->isSystemUser()) { - if (!empty($data['role']) && !in_array(UserRole::SUPER_ADMIN_FO, $data['role'], true)) { + if (!empty($data['role']) && !\in_array(UserRole::SUPER_ADMIN_FO, $data['role'], true)) { throw new Exception('You can not remove admin role from the "System" user', 412); } - if (isset($data['status']) && $data['status'] === User::STATUS_INACTIVE) { + if (isset($data['status']) && $data['status'] === UserSuperClass::STATUS_INACTIVE) { throw new Exception('You can not deactivate the "System" user', 412); } } @@ -215,31 +127,27 @@ private function verifySystemUserUpdate(User $user, array $data = []) public function updateUserAnr(User $user, array $data): void { - $connectedUserName = $this->connectedUserService->getConnectedUser()->getFirstname() - . ' ' . $this->connectedUserService->getConnectedUser()->getLastname(); - if (isset($data['anrs'])) { - $assignedAnrIds = array_map('intval', array_column($data['anrs'], 'id')); + if (!empty($data['anrs'])) { + $assignedAnrIds = array_map('\intval', array_column($data['anrs'], 'id')); foreach ($user->getUserAnrs() as $userAnr) { $assignedAnrKey = array_search($userAnr->getAnr()->getId(), $assignedAnrIds, true); - if ($assignedAnrKey === false) { - $user->removeUserAnr($userAnr); - } else { - $userAnr - ->setRwd($data['anrs'][$assignedAnrKey]['rwd']) - ->setUpdater($connectedUserName); + if ($assignedAnrKey !== false) { + $userAnr->setRwd((int)$data['anrs'][$assignedAnrKey]['rwd']) + ->setUpdater($this->connectedUser->getEmail()); unset($data['anrs'][$assignedAnrKey]); + } else { + $user->removeUserAnr($userAnr); } } - foreach ($data['anrs'] as $anr) { + foreach ($data['anrs'] as $anrData) { + /** @var Anr $anr */ + $anr = $this->anrTable->findById($anrData['id']); $user->addUserAnr( - (new UserAnr()) - ->setAnr($this->anrTable->findById($anr['id'])) - ->setRwd($anr['rwd']) - ->setCreator($connectedUserName) + (new UserAnr())->setAnr($anr)->setRwd($anrData['rwd'])->setCreator($this->connectedUser->getEmail()) ); } - $this->userTable->saveEntity($user); + $this->userTable->save($user); } } } diff --git a/src/Stats/Controller/StatsAnrsSettingsController.php b/src/Stats/Controller/StatsAnrsSettingsController.php index ea8e4b16..82ab3149 100644 --- a/src/Stats/Controller/StatsAnrsSettingsController.php +++ b/src/Stats/Controller/StatsAnrsSettingsController.php @@ -1,4 +1,9 @@ statsSettingsService = $statsSettingsService; } public function patchList($data): JsonModel diff --git a/src/Stats/Controller/StatsController.php b/src/Stats/Controller/StatsController.php index 577b0920..d43f9382 100644 --- a/src/Stats/Controller/StatsController.php +++ b/src/Stats/Controller/StatsController.php @@ -1,4 +1,9 @@ getStatsQueryParamsValidator = $getStatsQueryParamsValidator; - $this->getProcessedStatsQueryParamsValidator = $getProcessedStatsQueryParamsValidator; - $this->statsAnrService = $statsAnrService; } public function getList(): JsonModel @@ -37,14 +29,15 @@ public function getList(): JsonModel if (!$this->getStatsQueryParamsValidator->isValid($this->params()->fromQuery())) { throw new Exception( 'Query params validation errors: [ ' - . json_encode($this->getStatsQueryParamsValidator->getErrorMessages()), + . json_encode($this->getStatsQueryParamsValidator->getErrorMessages(), JSON_THROW_ON_ERROR) + . ']', 400 ); } try { $stats = $this->statsAnrService->getStats($this->getStatsQueryParamsValidator->getValidData()); - } catch (UserNotAuthorizedException | AccessForbiddenException $e) { + } catch (AccessForbiddenException) { $stats = []; $this->getResponse()->setStatusCode(403); } @@ -59,14 +52,17 @@ public function getProcessedListAction(): JsonModel if (!$this->getProcessedStatsQueryParamsValidator->isValid($this->params()->fromQuery())) { throw new Exception( 'Query params validation errors: [ ' - . json_encode($this->getProcessedStatsQueryParamsValidator->getErrorMessages()), + . json_encode($this->getProcessedStatsQueryParamsValidator->getErrorMessages(), JSON_THROW_ON_ERROR) + . ']', 400 ); } try { - $stats = $this->statsAnrService->getProcessedStats($this->getProcessedStatsQueryParamsValidator->getValidData()); - } catch (UserNotAuthorizedException | AccessForbiddenException $e) { + $stats = $this->statsAnrService->getProcessedStats( + $this->getProcessedStatsQueryParamsValidator->getValidData() + ); + } catch (AccessForbiddenException) { $stats = []; $this->getResponse()->setStatusCode(403); } diff --git a/src/Stats/Controller/StatsGeneralSettingsController.php b/src/Stats/Controller/StatsGeneralSettingsController.php index dd90b8a8..4078e51f 100644 --- a/src/Stats/Controller/StatsGeneralSettingsController.php +++ b/src/Stats/Controller/StatsGeneralSettingsController.php @@ -1,4 +1,9 @@ statsSettingsService = $statsSettingsService; } public function patchList($data): JsonModel diff --git a/src/Stats/Service/StatsAnrService.php b/src/Stats/Service/StatsAnrService.php index 977fb593..6c4e8952 100644 --- a/src/Stats/Service/StatsAnrService.php +++ b/src/Stats/Service/StatsAnrService.php @@ -1,29 +1,26 @@ anrTable = $anrTable; - $this->scaleTable = $scaleTable; - $this->informationalRiskTable = $informationalRiskTable; - $this->operationalRiskTable = $operationalRiskTable; - $this->referentialTable = $referentialTable; - $this->soaTable = $soaTable; - $this->statsApiProvider = $statsApiProvider; - $this->connectedUserService = $connectedUserService; - $this->userTable = $userTable; - $this->snapshotTable = $snapshotTable; - $this->apiKey = $config['statsApi']['apiKey']; + $this->connectedUser = $connectedUserService->getConnectedUser(); + $this->apiKey = $config['statsApi']['apiKey'] ?? ''; } - /** - * @throws UserNotAuthorizedException - * @throws EntityNotFoundException - */ public function isStatsAvailable(): bool { - $loggedInUser = $this->getValidatedLoggedInUser(); - if (!$loggedInUser->hasRole(UserRole::USER_ROLE_CEO)) { - $anrUuids = $this->getAvailableUserAnrsUuids($loggedInUser); + if ($this->apiKey === '') { + return false; + } + + if (!$this->connectedUser?->hasRole(UserRole::USER_ROLE_CEO)) { + $anrUuids = $this->getAvailableUserAnrsUuids(); if (empty($anrUuids)) { return false; } @@ -151,17 +111,14 @@ public function isStatsAvailable(): bool * * @return array * - * @throws UserNotAuthorizedException * @throws AccessForbiddenException * @throws Exception * @throws StatsFetchingException */ public function getStats(array $validatedParams): array { - $loggedInUser = $this->getValidatedLoggedInUser(); - if (empty($validatedParams['type'])) { - throw new \LogicException("Filter parameter 'type' is mandatory to get the stats."); + throw new LogicException("Filter parameter 'type' is mandatory to get the stats."); } $requestParams['type'] = $validatedParams['type']; @@ -173,7 +130,7 @@ public function getStats(array $validatedParams): array $requestParams['get_last'] = true; } - $anrUuids = $this->getFilteredAnrUuids($validatedParams, $loggedInUser); + $anrUuids = $this->getFilteredAnrUuids($validatedParams); if (!empty($anrUuids)) { $requestParams['anrs'] = $anrUuids; } @@ -186,7 +143,6 @@ public function getStats(array $validatedParams): array $statsData = $this->statsApiProvider->getStatsData($requestParams); - // TODO: make a response data formatter with passing the aggregation period param. if ($requestParams['type'] === StatsDataObject::TYPE_RISK) { $statsData = $this->formatRisksStatsData($statsData); } elseif (in_array( @@ -205,17 +161,12 @@ public function getStats(array $validatedParams): array } /** - * @throws AccessForbiddenException - * @throws StatsFetchingException - * @throws UserNotAuthorizedException - * @throws WrongResponseFormatException + * @throws LogicException|AccessForbiddenException|WrongResponseFormatException|StatsFetchingException */ public function getProcessedStats(array $validatedParams): array { - $loggedInUser = $this->getValidatedLoggedInUser(); - if (empty($validatedParams['processor']) || empty($validatedParams['type'])) { - throw new \LogicException("Filter parameters 'processor' and 'type' are mandatory to get the stats."); + throw new LogicException("Filter parameters 'processor' and 'type' are mandatory to get the stats."); } $requestParams['processor'] = $validatedParams['processor']; $requestParams['processor_params'] = $validatedParams['processor_params']; @@ -223,14 +174,15 @@ public function getProcessedStats(array $validatedParams): array $requestParams['date_to'] = $this->getPreparedDateTo($validatedParams); $requestParams['type'] = $validatedParams['type']; - $anrUuids = $this->getFilteredAnrUuids(['anrs' => []], $loggedInUser); + $anrUuids = $this->getFilteredAnrUuids(['anrs' => []]); if (!empty($anrUuids)) { $requestParams['anrs'] = $anrUuids; } + /* Seems not used. if (!empty($validatedParams['nbdays'])) { $validatedParams['nbdays']; - } + }*/ return $this->formatProcessedStatsData($this->statsApiProvider->getProcessedStatsData($requestParams)); } @@ -239,7 +191,7 @@ public function getProcessedStats(array $validatedParams): array * Collects the statistics for today. * * @param int[] $anrIds List of Anr IDs to use for the stats collection. - * @param bool $forceUpdate Whether or not overwrite the data if already presented for today. + * @param bool $forceUpdate Whether overwrite the data if already presented for today. * * @return array * @@ -247,7 +199,6 @@ public function getProcessedStats(array $validatedParams): array * @throws StatsFetchingException * @throws StatsSendingException * @throws WrongResponseFormatException - * @throws EntityNotFoundException */ public function collectStats(array $anrIds = [], bool $forceUpdate = false): array { @@ -364,8 +315,8 @@ private function collectAnrStatsForRiskThreatVulnerabilityAndCartography(Anr $an StatsDataObject::TYPE_VULNERABILITY => $informationalRisksValues[StatsDataObject::TYPE_VULNERABILITY], StatsDataObject::TYPE_CARTOGRAPHY => [ 'scales' => [ - 'impact' => $scalesRanges[Scale::TYPE_IMPACT], - 'probability' => $scalesRanges[Scale::TYPE_THREAT], + 'impact' => $scalesRanges[ScaleSuperClass::TYPE_IMPACT], + 'probability' => $scalesRanges[ScaleSuperClass::TYPE_THREAT], 'likelihood' => $likelihoodScales, ], 'risks' => [ @@ -399,17 +350,17 @@ private function collectAnrStatsForCompliance(Anr $anr): array } $currentCategoryValues = [ - 'label1' => $soaCategory->getlabel1(), - 'label2' => $soaCategory->getlabel2(), - 'label3' => $soaCategory->getlabel3(), - 'label4' => $soaCategory->getlabel4(), + 'label1' => $soaCategory->getlabel(1), + 'label2' => $soaCategory->getlabel(2), + 'label3' => $soaCategory->getlabel(3), + 'label4' => $soaCategory->getlabel(4), 'controls' => [], ]; $targetCategoryValues = [ - 'label1' => $soaCategory->getlabel1(), - 'label2' => $soaCategory->getlabel2(), - 'label3' => $soaCategory->getlabel3(), - 'label4' => $soaCategory->getlabel4(), + 'label1' => $soaCategory->getlabel(1), + 'label2' => $soaCategory->getlabel(2), + 'label3' => $soaCategory->getlabel(3), + 'label4' => $soaCategory->getlabel(4), 'controls' => [], ]; $targetSoaCount = 0; @@ -421,12 +372,12 @@ private function collectAnrStatsForCompliance(Anr $anr): array } $currentCategoryValues['controls'][] = [ 'code' => $measure->getCode(), - 'measure' => (string)$measure->getUuid(), + 'measure' => $measure->getUuid(), 'value' => $soa->getEx() === 1 ? '0.00' : bcmul((string)$soa->getCompliance(), '0.20', 2), ]; $targetCategoryValues['controls'][] = [ 'code' => $measure->getCode(), - 'measure' => (string)$measure->getUuid(), + 'measure' => $measure->getUuid(), 'value' => $soa->getEx() === 1 ? '0' : '1', ]; @@ -449,19 +400,19 @@ private function collectAnrStatsForCompliance(Anr $anr): array ), '0.2', 2); $targetCategoryValues['value'] = bcdiv((string)$targetSoaCount, (string)$currentControlsNumber, 2); - if (!isset($complianceStatsValues[(string)$reference->getUuid()])) { - $complianceStatsValues[(string)$reference->getUuid()] = [ - 'referential' => (string)$reference->getUuid(), - 'label1' => $reference->getLabel1(), - 'label2' => $reference->getLabel2(), - 'label3' => $reference->getLabel3(), - 'label4' => $reference->getLabel4(), + if (!isset($complianceStatsValues[$reference->getUuid()])) { + $complianceStatsValues[$reference->getUuid()] = [ + 'referential' => $reference->getUuid(), + 'label1' => $reference->getLabel(1), + 'label2' => $reference->getLabel(2), + 'label3' => $reference->getLabel(3), + 'label4' => $reference->getLabel(4), 'current' => [], 'target' => [], ]; } - $complianceStatsValues[(string)$reference->getUuid()]['current'][] = $currentCategoryValues; - $complianceStatsValues[(string)$reference->getUuid()]['target'][] = $targetCategoryValues; + $complianceStatsValues[$reference->getUuid()]['current'][] = $currentCategoryValues; + $complianceStatsValues[$reference->getUuid()]['target'][] = $targetCategoryValues; } } } @@ -472,9 +423,9 @@ private function collectAnrStatsForCompliance(Anr $anr): array private function prepareScalesRanges(Anr $anr): array { $scalesRanges = [ - Scale::TYPE_IMPACT => [], - Scale::TYPE_THREAT => [], - Scale::TYPE_VULNERABILITY => [], + ScaleSuperClass::TYPE_IMPACT => [], + ScaleSuperClass::TYPE_THREAT => [], + ScaleSuperClass::TYPE_VULNERABILITY => [], ]; $scales = $this->scaleTable->findByAnr($anr); foreach ($scales as $scale) { @@ -487,9 +438,9 @@ private function prepareScalesRanges(Anr $anr): array private function calculateScalesColumnValues(array $scalesRanges): array { $headersResult = []; - foreach ($scalesRanges[Scale::TYPE_IMPACT] as $i) { - foreach ($scalesRanges[Scale::TYPE_THREAT] as $t) { - foreach ($scalesRanges[Scale::TYPE_VULNERABILITY] as $v) { + foreach ($scalesRanges[ScaleSuperClass::TYPE_IMPACT] as $i) { + foreach ($scalesRanges[ScaleSuperClass::TYPE_THREAT] as $t) { + foreach ($scalesRanges[ScaleSuperClass::TYPE_VULNERABILITY] as $v) { $value = -1; if ($i !== -1 && $t !== -1 && $v !== -1) { $value = $t * $v; @@ -575,7 +526,7 @@ private function getRiskContext(Anr $anr, int $maxImpact, int $maxRiskValue): ar private function getRiskValues(array $risksValues, array $riskContext, string $amvKey, array $riskData): array { $objectId = (string)$riskData['objectId']; - $isScopeGlobal = $riskData['scope'] === MonarcObject::SCOPE_GLOBAL; + $isScopeGlobal = $riskData['scope'] === ObjectSuperClass::SCOPE_GLOBAL; $riskKey = $isScopeGlobal ? 0 : $riskData['id']; if (!$isScopeGlobal || empty($risksValues[$objectId][$amvKey][$riskKey]) @@ -589,7 +540,7 @@ private function getRiskValues(array $risksValues, array $riskContext, string $a private function getThreatsValues(array $threatsValues, string $key, array $riskData): array { - $isScopeGlobal = $riskData['scope'] === MonarcObject::SCOPE_GLOBAL; + $isScopeGlobal = $riskData['scope'] === ObjectSuperClass::SCOPE_GLOBAL; $threatKey = $isScopeGlobal ? 0 : (string)$riskData['threatId']; if (!$isScopeGlobal || empty($threatsValues[$key][$threatKey]) @@ -612,7 +563,7 @@ private function getThreatsValues(array $threatsValues, string $key, array $risk private function getVulnerabilitiesValues(array $vulnerabilitiesValues, string $key, array $riskData): array { - $isScopeGlobal = $riskData['scope'] === MonarcObject::SCOPE_GLOBAL; + $isScopeGlobal = $riskData['scope'] === ObjectSuperClass::SCOPE_GLOBAL; $vulnerabilityKey = $isScopeGlobal ? 0 : (string)$riskData['vulnerabilityId']; if (!$isScopeGlobal || empty($vulnerabilitiesValues[$key][$vulnerabilityKey]) @@ -845,13 +796,12 @@ private function getTotalValue(array $values): int /** * @throws AccessForbiddenException - * @throws EntityNotFoundException */ - private function getFilteredAnrUuids(array $validatedParams, UserSuperClass $loggedInUser): array + private function getFilteredAnrUuids(array $validatedParams): array { $anrUuids = []; - if (!$loggedInUser->hasRole(UserRole::USER_ROLE_CEO)) { - $anrUuids = $this->getAvailableUserAnrsUuids($loggedInUser, $validatedParams['anrs']); + if (!$this->connectedUser?->hasRole(UserRole::USER_ROLE_CEO)) { + $anrUuids = $this->getAvailableUserAnrsUuids($validatedParams['anrs']); if (empty($anrUuids)) { throw new AccessForbiddenException(); } @@ -915,16 +865,17 @@ private function formatRisksStatsData(array $statsData): array if (empty($risksData['risks']['current']) || empty($risksData['risks']['residual'])) { continue; } - $anrUuids[] = $data->getAnr(); - $formattedResult[$data->getAnr()] = [ + $anrUuid = $data->getAnr(); + $anrUuids[] = $anrUuid; + $formattedResult[$anrUuid] = [ 'current' => [ 'category' => '', - 'uuid' => $data->getAnr(), + 'uuid' => $anrUuid, 'series' => $this->getSeriesForType('current', $risksData), ], 'residual' => [ 'category' => '', - 'uuid' => $data->getAnr(), + 'uuid' => $anrUuid, 'series' => $this->getSeriesForType('residual', $risksData), ], ]; @@ -943,7 +894,7 @@ private function formatRisksStatsData(array $statsData): array 'residual' => array_column($formattedResult, 'residual'), ]; foreach ($formattedResult as $key => &$value) { - usort($value, function ($a, $b) { + usort($value, static function ($a, $b) { return $a['category'] <=> $b['category']; }); } @@ -980,11 +931,11 @@ private function formatThreatsOrVulnerabilitiesStatsData(array $statsData): arra return []; } - $userLanguageNumber = $this->connectedUserService->getConnectedUser()->getLanguage(); + $userLanguageNumber = $this->connectedUser !== null ? $this->connectedUser->getLanguage() : 1; $formattedResult = []; foreach ($statsData as $data) { $anrUuid = $data->getAnr(); - $anr = $this->anrTable->findByUuid($anrUuid); + $anr = $this->anrTable->findOneByUuid($anrUuid); if ($anr === null) { continue; } @@ -1060,7 +1011,7 @@ private function formatCartographyStatsData(array $statsData): array $formattedResult = []; foreach ($statsData as $dataSet) { $anrUuid = $dataSet->getAnr(); - $anr = $this->anrTable->findByUuid($anrUuid); + $anr = $this->anrTable->findOneByUuid($anrUuid); if ($anr === null) { continue; } @@ -1099,9 +1050,10 @@ private function formatCartographyStatsData(array $statsData): array $minProbability = empty($data['scales']['probability']) ? 0 : min($data['scales']['probability']); foreach ($scalesImpact as $impactValue) { - $y = $this->approximate($impactValue, $minImpact, $maxImpact, 0, 4); + $y = $this->convertValueWithinNewScalesRange($impactValue, $minImpact, $maxImpact, 0, 4); foreach ($data['scales']['likelihood'] as $likelihoodValue) { - $x = $this->approximate($likelihoodValue, $minLikelihood, $maxLikelihood, 0, 20); + $x = $this + ->convertValueWithinNewScalesRange($likelihoodValue, $minLikelihood, $maxLikelihood, 0, 20); $seriesKey = $y . $x; if (!isset($formattedResult[$anrUuid]['informational']['currentInfo']['series'][$seriesKey])) { $formattedResult[$anrUuid]['informational']['currentInfo']['series'][$seriesKey] = [ @@ -1129,7 +1081,8 @@ private function formatCartographyStatsData(array $statsData): array } foreach ($data['scales']['probability'] as $probabilityValue) { - $x = $this->approximate($probabilityValue, $minProbability, $maxProbability, 0, 4); + $x = $this + ->convertValueWithinNewScalesRange($probabilityValue, $minProbability, $maxProbability, 0, 4); $seriesKey = $y . $x; if (!isset($formattedResult[$anrUuid]['operational']['currentOp']['series'][$seriesKey])) { $formattedResult[$anrUuid]['operational']['currentOp']['series'][$seriesKey] = [ @@ -1189,7 +1142,7 @@ private function formatCartographyStatsData(array $statsData): array }); } unset($value); - foreach ($formattedResult['operational'] as $key => &$value) { + foreach ($formattedResult['operational'] as &$value) { usort($value, static function ($a, $b) { return $a['category'] <=> $b['category']; }); @@ -1199,19 +1152,6 @@ private function formatCartographyStatsData(array $statsData): array return $formattedResult; } - private function approximate($x, $minorig, $maxorig, $mindest, $maxdest, $defaultvalue = -1) - { - if ($x === $maxorig) { - return $maxdest; - } - - if ($x !== -1 && ($maxorig - $minorig) !== -1) { - return min(max(round(($x / ($maxorig - $minorig + 1)) * ($maxdest - $mindest + 1)), $mindest), $maxdest); - } - - return $defaultvalue; - } - /** * @param StatsDataObject[] $statsData * @@ -1226,7 +1166,7 @@ private function formatComplianceStatsData(array $statsData): array $formattedResult = []; foreach ($statsData as $data) { $anrUuid = $data->getAnr(); - $anr = $this->anrTable->findByUuid($anrUuid); + $anr = $this->anrTable->findOneByUuid($anrUuid); if ($anr === null) { continue; } @@ -1292,7 +1232,7 @@ private function getMeasuresData(array $data, int $anrLanguage): array private function formatProcessedStatsData(array $data): array { - $userLanguageNumber = $this->connectedUserService->getConnectedUser()->getLanguage(); + $userLanguageNumber = $this->connectedUser !== null ? $this->connectedUser->getLanguage() : 1; $formattedResponse = []; foreach ($data as $processedStats) { $dataRow = $processedStats; @@ -1321,29 +1261,10 @@ private function formatProcessedStatsData(array $data): array return $formattedResponse; } - /** - * @throws UserNotAuthorizedException - */ - private function getValidatedLoggedInUser(): UserSuperClass - { - $loggedInUser = $this->connectedUserService->getConnectedUser(); - if ($loggedInUser === null) { - throw new UserNotAuthorizedException(); - } - - return $loggedInUser; - } - - /** - * @throws EntityNotFoundException - */ - private function getAvailableUserAnrsUuids(UserSuperClass $loggedInUser, array $anrIds = []): array + private function getAvailableUserAnrsUuids(array $anrIds = []): array { $anrUuids = []; - /** @var User $user */ - // We do this trick to get the User object from FO side instead of Core. - $user = $this->userTable->findById($loggedInUser->getId()); - $userAnrs = $user->getUserAnrs(); + $userAnrs = $this->connectedUser !== null ? $this->connectedUser->getUserAnrs() : []; $snapshotAnrsIds = []; if (!$userAnrs->isEmpty()) { $snapshots = $this->snapshotTable->findAll(); diff --git a/src/Stats/Service/StatsSettingsService.php b/src/Stats/Service/StatsSettingsService.php index 102f854f..e6340871 100644 --- a/src/Stats/Service/StatsSettingsService.php +++ b/src/Stats/Service/StatsSettingsService.php @@ -4,7 +4,7 @@ use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; -use Monarc\FrontOffice\Model\Table\AnrTable; +use Monarc\FrontOffice\Table\AnrTable; use Monarc\FrontOffice\Stats\Exception\StatsGetClientException; use Monarc\FrontOffice\Stats\Exception\StatsUpdateClientException; use Monarc\FrontOffice\Stats\Provider\StatsApiProvider; @@ -62,9 +62,9 @@ public function updateAnrsSettings(array $anrSettings): array 'isStatsCollected' => $anr->isStatsCollected(), ]; - $this->anrTable->saveEntity($anr, false); + $this->anrTable->save($anr, false); } - $this->anrTable->getDb()->flush(); + $this->anrTable->flush(); return $updatedAnrsSettings; } @@ -76,7 +76,7 @@ public function getGeneralSettings(): array { try { $client = $this->statsApiProvider->getClient(); - } catch (\Throwable $e) { + } catch (\Throwable) { } return [ @@ -93,8 +93,9 @@ public function updateGeneralSettings(array $data): void throw new StatsUpdateClientException('The option `is_sharing_enabled` is mandatory.'); } - $this->statsApiProvider->updateClient([ - 'is_sharing_enabled' => (bool)$data['is_sharing_enabled'], - ]); + try { + $this->statsApiProvider->updateClient(['is_sharing_enabled' => (bool)$data['is_sharing_enabled']]); + } catch (\Throwable) { + } } } diff --git a/src/Stats/Validator/GetProcessedStatsQueryParamsValidator.php b/src/Stats/Validator/GetProcessedStatsQueryParamsValidator.php index db949d57..5ff9b52e 100644 --- a/src/Stats/Validator/GetProcessedStatsQueryParamsValidator.php +++ b/src/Stats/Validator/GetProcessedStatsQueryParamsValidator.php @@ -5,22 +5,16 @@ use DateTime; use Laminas\Filter\StringTrim; use Laminas\InputFilter\ArrayInput; -use Laminas\InputFilter\InputFilter; use Laminas\Validator\Callback; use Laminas\Validator\Date; use Laminas\Validator\Digits; use Laminas\Validator\InArray; +use Monarc\Core\Validator\InputValidator\AbstractInputValidator; use Monarc\FrontOffice\Stats\DataObject\StatsDataObject; use Monarc\FrontOffice\Stats\Service\StatsAnrService; -use Monarc\FrontOffice\Validator\InputValidator\AbstractMonarcInputValidator; -class GetProcessedStatsQueryParamsValidator extends AbstractMonarcInputValidator +class GetProcessedStatsQueryParamsValidator extends AbstractInputValidator { - public function __construct(InputFilter $inputFilter) - { - parent::__construct($inputFilter); - } - protected function getRules(): array { return [ diff --git a/src/Stats/Validator/GetProcessedStatsQueryParamsValidatorFactory.php b/src/Stats/Validator/GetProcessedStatsQueryParamsValidatorFactory.php deleted file mode 100644 index 60bf77c0..00000000 --- a/src/Stats/Validator/GetProcessedStatsQueryParamsValidatorFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -get(Factory::class); - - return new $requestedName($inputFilterFactory->createInputFilter([])); - } -} - diff --git a/src/Stats/Validator/GetStatsQueryParamsValidator.php b/src/Stats/Validator/GetStatsQueryParamsValidator.php index 64ee304e..4ad4fb72 100644 --- a/src/Stats/Validator/GetStatsQueryParamsValidator.php +++ b/src/Stats/Validator/GetStatsQueryParamsValidator.php @@ -6,27 +6,22 @@ use Laminas\Filter\Boolean; use Laminas\Filter\StringTrim; use Laminas\InputFilter\ArrayInput; -use Laminas\InputFilter\InputFilter; use Laminas\Validator\Callback; use Laminas\Validator\Date; use Laminas\Validator\Digits; use Laminas\Validator\InArray; -use Monarc\FrontOffice\Model\Table\AnrTable; +use Monarc\Core\Validator\InputValidator\AbstractInputValidator; +use Monarc\Core\Validator\InputValidator\InputValidationTranslator; +use Monarc\FrontOffice\Table\AnrTable; use Monarc\FrontOffice\Stats\DataObject\StatsDataObject; use Monarc\FrontOffice\Stats\Service\StatsAnrService; use Monarc\FrontOffice\Validator\FieldValidator\AnrExistenceValidator; -use Monarc\FrontOffice\Validator\InputValidator\AbstractMonarcInputValidator; -class GetStatsQueryParamsValidator extends AbstractMonarcInputValidator +class GetStatsQueryParamsValidator extends AbstractInputValidator { - /** @var AnrTable */ - private $anrTable; - - public function __construct(InputFilter $inputFilter, AnrTable $anrTable) + public function __construct(array $config, InputValidationTranslator $translator, private AnrTable $anrTable) { - $this->anrTable = $anrTable; - - parent::__construct($inputFilter); + parent::__construct($config, $translator); } protected function getRules(): array diff --git a/src/Stats/Validator/GetStatsQueryParamsValidatorFactory.php b/src/Stats/Validator/GetStatsQueryParamsValidatorFactory.php deleted file mode 100644 index 0ffbcdf3..00000000 --- a/src/Stats/Validator/GetStatsQueryParamsValidatorFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -get(Factory::class); - - return new $requestedName($inputFilterFactory->createInputFilter([]), $container->get(AnrTable::class)); - } -} - diff --git a/src/Table/AmvTable.php b/src/Table/AmvTable.php new file mode 100755 index 00000000..9f93516e --- /dev/null +++ b/src/Table/AmvTable.php @@ -0,0 +1,68 @@ +getRepository()->createQueryBuilder('amv') + ->innerJoin('amv.asset', 'a') + ->where('amv.anr = :anr') + ->andWhere('a.uuid = :asset_uuid') + ->andWhere('a.anr = :anr') + ->andWhere('amv.position = :position') + ->setParameter('anr', $asset->getAnr()) + ->setParameter('asset_uuid', $asset->getUuid()) + ->setParameter('position', $position) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + public function findByAmvItemsUuidsAndAnr( + string $assetUuid, + string $threatUuid, + string $vulnerabilityUuid, + Anr $anr + ): ?Amv { + return $this->getRepository() + ->createQueryBuilder('amv') + ->innerJoin('amv.asset', 'a') + ->innerJoin('amv.threat', 't') + ->innerJoin('amv.vulnerability', 'v') + ->andWhere('amv.anr = :anr') + ->andWhere('a.uuid = :assetUuid') + ->andWhere('a.anr = :anr') + ->andWhere('t.uuid = :threatUuid') + ->andWhere('t.anr = :anr') + ->andWhere('v.uuid = :vulnerabilityUuid') + ->andWhere('v.anr = :anr') + ->setParameter('assetUuid', $assetUuid) + ->setParameter('threatUuid', $threatUuid) + ->setParameter('vulnerabilityUuid', $vulnerabilityUuid) + ->setParameter('anr', $anr) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Table/AnrInstanceMetadataFieldTable.php b/src/Table/AnrInstanceMetadataFieldTable.php new file mode 100644 index 00000000..a648e2a9 --- /dev/null +++ b/src/Table/AnrInstanceMetadataFieldTable.php @@ -0,0 +1,20 @@ +entityClass = Anr::class; + parent::__construct($entityManager, $entityName); } - /** - * @param string $uuid - * - * @return Anr|null - * @throws NonUniqueResultException - */ - public function findByUuid(string $uuid): ?Anr + public function findOneByUuid(string $uuid): ?Anr { return $this->getRepository()->createQueryBuilder('a') ->where('a.uuid = :uuid') @@ -67,7 +53,7 @@ public function fetchAnrsExcludeSnapshotsWithUserRights(int $userId): array $queryBuilder = $this->getRepository()->createQueryBuilder('a'); return $queryBuilder - ->select('a.id, a.label1, a.label2, a.label3, a.label4, (CASE WHEN ua.rwd IS NULL THEN -1 ELSE ua.rwd END) AS rwd') + ->select('a.id, a.label, (CASE WHEN ua.rwd IS NULL THEN -1 ELSE ua.rwd END) AS rwd') ->leftJoin(UserAnr::class, 'ua', Expr\Join::WITH, 'ua.anr = a AND ua.user = :userId') ->where($queryBuilder->expr()->notIn('a.id', $excludedSnapshots->getDQL())) ->setParameter('userId', $userId) @@ -103,9 +89,7 @@ public function findAllExcludeSnapshots(): array */ public function findVisibleOnDashboard(): array { - return $this - ->getRepository() - ->createQueryBuilder('a') + return $this->getRepository()->createQueryBuilder('a') ->where('a.isVisibleOnDashboard = 1') ->getQuery() ->getResult(); @@ -113,9 +97,7 @@ public function findVisibleOnDashboard(): array private function getSnapshotsIdsQueryBuilder(): QueryBuilder { - return $this->getDb() - ->getEntityManager() - ->createQueryBuilder() + return $this->entityManager->createQueryBuilder() ->select('anr.id') ->from(Snapshot::class, 's') ->join(Anr::class, 'anr', Expr\Join::WITH, 's.anr = anr'); diff --git a/src/Table/AssetTable.php b/src/Table/AssetTable.php new file mode 100755 index 00000000..22834838 --- /dev/null +++ b/src/Table/AssetTable.php @@ -0,0 +1,24 @@ +getRepository()->findAll(); + } + + public function findFirstClient(): Client + { + $client = $this->getRepository()->createQueryBuilder('c') + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + if ($client === null) { + throw new EntityNotFoundException('There are no clients exist.'); + } + + return $client; + } +} diff --git a/src/Table/DeliveryTable.php b/src/Table/DeliveryTable.php new file mode 100755 index 00000000..fd49cb57 --- /dev/null +++ b/src/Table/DeliveryTable.php @@ -0,0 +1,35 @@ +getRepository()->createQueryBuilder('d') + ->where('d.anr = :anr') + ->andWhere('d.docType = :docType') + ->setParameter('anr', $anr) + ->setParameter('docType', $docType) + ->orderBy('d.createdAt', Criteria::DESC) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Table/InstanceConsequenceTable.php b/src/Table/InstanceConsequenceTable.php new file mode 100755 index 00000000..f603116f --- /dev/null +++ b/src/Table/InstanceConsequenceTable.php @@ -0,0 +1,43 @@ +getRepository()->createQueryBuilder('ic'); + + return $queryBuilder + ->innerJoin('ic.instance', 'i') + ->where('ic.anr = :anr') + ->setParameter(':anr', $anr) + ->andWhere($queryBuilder->expr()->orX( + $queryBuilder->expr()->neq('ic.c', -1), + $queryBuilder->expr()->neq('ic.i', -1), + $queryBuilder->expr()->neq('ic.d', -1), + $queryBuilder->expr()->neq('i.c', -1), + $queryBuilder->expr()->neq('i.i', -1), + $queryBuilder->expr()->neq('i.d', -1) + )) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT) !== null; + } +} diff --git a/src/Table/InstanceMetadataTable.php b/src/Table/InstanceMetadataTable.php new file mode 100644 index 00000000..cba5ecdf --- /dev/null +++ b/src/Table/InstanceMetadataTable.php @@ -0,0 +1,36 @@ +getRepository()->createQueryBuilder('im') + ->where('im.instance = :instance') + ->andWhere('im.anrInstanceMetadataField = :anrInstanceMetadataField') + ->setParameter('instance', $instance) + ->setParameter('anrInstanceMetadataField', $anrInstanceMetadataField) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Model/Table/InstanceRiskOpTable.php b/src/Table/InstanceRiskOpTable.php similarity index 58% rename from src/Model/Table/InstanceRiskOpTable.php rename to src/Table/InstanceRiskOpTable.php index b3a28cc8..3cf89839 100755 --- a/src/Model/Table/InstanceRiskOpTable.php +++ b/src/Table/InstanceRiskOpTable.php @@ -1,33 +1,29 @@ -entityClass = InstanceRiskOp::class; + parent::__construct($entityManager, $entityName); } public function findByAnrInstanceAndRolfRisk(Anr $anr, Instance $instance, RolfRisk $rolfRisk): ?InstanceRiskOp @@ -45,6 +41,53 @@ public function findByAnrInstanceAndRolfRisk(Anr $anr, Instance $instance, RolfR ->getOneOrNullResult(); } + /** + * @return InstanceRiskOp[] + */ + public function findByAnrAndRolfRisk(Anr $anr, RolfRisk $rolfRisk): array + { + return $this->getRepository() + ->createQueryBuilder('oir') + ->where('oir.anr = :anr') + ->andWhere('oir.rolfRisk = :rolfRisk') + ->setParameter('anr', $anr) + ->setParameter('rolfRisk', $rolfRisk) + ->getQuery() + ->getResult(); + } + + /** + * @return InstanceRiskOp[] + */ + public function findByAnrAndInstance(Anr $anr, Instance $instance): array + { + return $this->getRepository() + ->createQueryBuilder('oprisk') + ->where('oprisk.anr = :anr') + ->andWhere('oprisk.instance = :instance') + ->setParameter('anr', $anr) + ->setParameter('instance', $instance) + ->getQuery() + ->getResult(); + } + + /** + * @return InstanceRiskOp[] + */ + public function findByAnrAndOrderByParams(Anr $anr, array $orderBy = []): array + { + $queryBuilder = $this->getRepository()->createQueryBuilder('oprisk') + ->innerJoin('oprisk.instance', 'i') + ->where('oprisk.anr = :anr') + ->setParameter('anr', $anr); + + foreach ($orderBy as $fieldName => $order) { + $queryBuilder->addOrderBy($fieldName, $order); + } + + return $queryBuilder->getQuery()->getResult(); + } + /** * @return InstanceRiskOp[] */ @@ -67,7 +110,7 @@ public function findByAnrInstancesAndFilterParams(Anr $anr, array $instancesIds, $language = $anr->getLanguage(); $queryBuilder = $this->getRepository()->createQueryBuilder('iro') ->innerJoin('iro.instance', 'i') - ->innerJoin('i.asset', 'a', Join::WITH, 'a.type = ' . Asset::TYPE_PRIMARY) + ->innerJoin('i.asset', 'a', Join::WITH, 'a.type = ' . AssetSuperClass::TYPE_PRIMARY) ->where('iro.anr = :anr') ->setParameter('anr', $anr); @@ -85,9 +128,9 @@ public function findByAnrInstancesAndFilterParams(Anr $anr, array $instancesIds, } if (isset($filterParams['kindOfMeasure'])) { - if ((int)$filterParams['kindOfMeasure'] === InstanceRiskOp::KIND_NOT_TREATED) { + if ((int)$filterParams['kindOfMeasure'] === InstanceRiskOpSuperClass::KIND_NOT_TREATED) { $queryBuilder->andWhere( - 'iro.kindOfMeasure IS NULL OR iro.kindOfMeasure = ' . InstanceRiskOp::KIND_NOT_TREATED + 'iro.kindOfMeasure IS NULL OR iro.kindOfMeasure = ' . InstanceRiskOpSuperClass::KIND_NOT_TREATED ); } else { $queryBuilder->andWhere('iro.kindOfMeasure = :kindOfMeasure') @@ -146,4 +189,41 @@ public function findByAnrInstancesAndFilterParams(Anr $anr, array $instancesIds, return $queryBuilder->getQuery()->getResult(); } + + /** + * @return InstanceRiskOp[] + */ + public function findByObjectAndRolfRisk(ObjectSuperClass $object, RolfRiskSuperClass $rolfRisk): array + { + return $this->getRepository()->createQueryBuilder('oprisk') + ->innerJoin('oprisk.object', 'o') + ->where('oprisk.anr = :anr') + ->andWhere('o.uuid = :objectUuid') + ->andWhere('o.anr = :anr') + ->andWhere('oprisk.rolfRisk = :rolfRisk') + ->setParameter('objectUuid', $object->getUuid()) + ->setParameter('anr', $object->getAnr()) + ->setParameter('rolfRisk', $rolfRisk) + ->getQuery() + ->getResult(); + } + + public function findRisksValuesForCartoStatsByAnr(Anr $anr): array + { + return $this->getRepository()->createQueryBuilder('iro') + ->select([ + 'iro as instanceRiskOp', + 'iro.cacheNetRisk as netRisk', + 'iro.cacheTargetedRisk as targetedRisk', + 'iro.kindOfMeasure as treatment', + 'IDENTITY(iro.rolfRisk) as id', + 'iro.netProb as netProb', + 'iro.targetedProb as targetedProb', + ]) + ->where('iro.anr = :anr') + ->setParameter(':anr', $anr) + ->andWhere("iro.cacheNetRisk != -1") + ->getQuery() + ->getResult(); + } } diff --git a/src/Table/InstanceRiskOwnerTable.php b/src/Table/InstanceRiskOwnerTable.php new file mode 100644 index 00000000..5cd63ec8 --- /dev/null +++ b/src/Table/InstanceRiskOwnerTable.php @@ -0,0 +1,51 @@ +getRepository()->createQueryBuilder('iro') + ->where('iro.anr = :anr') + ->andWhere('iro.name = :name') + ->setParameter('anr', $anr) + ->setParameter('name', $name) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + /** + * @return InstanceRiskOwner[] + */ + public function findByAnrAndFilterParams(Anr $anr, array $params): array + { + $queryBuilder = $this->getRepository()->createQueryBuilder('iro') + ->where('iro.anr = :anr') + ->orderBy('iro.name', Criteria::ASC) + ->setParameter('anr', $anr); + + if (!empty($params['name'])) { + $queryBuilder->andWhere('iro.name LIKE :name')->setParameter('name', '%' . $params['name'] . '%'); + } + + return $queryBuilder->getQuery()->getResult(); + } +} diff --git a/src/Table/InstanceRiskTable.php b/src/Table/InstanceRiskTable.php new file mode 100755 index 00000000..184c2f24 --- /dev/null +++ b/src/Table/InstanceRiskTable.php @@ -0,0 +1,271 @@ +getRepository()->createQueryBuilder('ir'); + + return $queryBuilder + ->where('ir.anr = :anr') + ->setParameter(':anr', $anr) + ->andWhere($queryBuilder->expr()->orX( + $queryBuilder->expr()->neq('ir.threatRate', -1), + $queryBuilder->expr()->neq('ir.vulnerabilityRate', -1) + )) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT) !== null; + } + + /** + * @return InstanceRisk[] + */ + public function findByInstanceAndInstanceRiskRelations( + InstanceSuperClass $instance, + InstanceRiskSuperClass $instanceRisk, + bool $excludeAmvFilter = false, + bool $includeAssetFilter = false + ) { + $queryBuilder = $this->getRepository() + ->createQueryBuilder('ir') + ->where('ir.instance = :instance') + ->setParameter('instance', $instance); + + if (!$excludeAmvFilter && $instanceRisk->getAmv() !== null) { + $queryBuilder + ->innerJoin('ir.amv', 'amv') + ->andWhere('amv.uuid = :amvUuid') + ->andWhere('amv.anr = :amvAnr') + ->setParameter('amvUuid', $instanceRisk->getAmv()->getUuid()) + ->setParameter('amvAnr', $instanceRisk->getAmv()->getAnr()); + } + if ($includeAssetFilter) { + $queryBuilder + ->innerJoin('ir.asset', 'a') + ->andWhere('a.uuid = :assetUuid') + ->andWhere('a.anr = :assetAnr') + ->setParameter('assetUuid', $instanceRisk->getAsset()->getUuid()) + ->setParameter('assetAnr', $instanceRisk->getAsset()->getAnr()); + } + + $queryBuilder + ->innerJoin('ir.threat', 'thr') + ->innerJoin('ir.vulnerability', 'vuln') + ->andWhere('thr.uuid = :threatUuid') + ->andWhere('thr.anr = :threatAnr') + ->andWhere('vuln.uuid = :vulnerabilityUuid') + ->andWhere('vuln.anr = :vulnerabilityAnr') + ->setParameter('threatUuid', $instanceRisk->getThreat()->getUuid()) + ->setParameter('threatAnr', $instanceRisk->getThreat()->getAnr()) + ->setParameter('vulnerabilityUuid', $instanceRisk->getVulnerability()->getUuid()) + ->setParameter('vulnerabilityAnr', $instanceRisk->getVulnerability()->getAnr()); + + if ($instanceRisk->isSpecific()) { + $queryBuilder->andWhere('ir.specific = ' . InstanceRiskSuperClass::TYPE_SPECIFIC); + } + + return $queryBuilder->getQuery()->getResult(); + } + + /** + * @return InstanceRisk[] + */ + public function findByAmv(Amv $amv): array + { + return $this->getRepository() + ->createQueryBuilder('ir') + ->innerJoin('ir.amv', 'amv') + ->where('amv.uuid = :amvUuid') + ->andWhere('amv.anr = :amvAnr') + ->setParameter('amvUuid', $amv->getUuid()) + ->setParameter('amvAnr', $amv->getAnr()) + ->getQuery() + ->getResult(); + } + + public function findRisksDataForStatsByAnr(Anr $anr): array + { + return $this->getRepository() + ->createQueryBuilder('ir') + ->select(' + ir.id, + IDENTITY(ir.asset) as assetId, + t.uuid as threatId, + v.uuid as vulnerabilityId, + ir.cacheMaxRisk, + ir.cacheTargetedRisk, + ir.threatRate, + ir.vulnerabilityRate, + i.c as instanceConfidentiality, + i.i as instanceIntegrity, + i.d as instanceAvailability, + t.c as threatConfidentiality, + t.i as threatIntegrity, + t.a as threatAvailability, + t.label1 as threatLabel1, + t.label2 as threatLabel2, + t.label3 as threatLabel3, + t.label4 as threatLabel4, + v.label1 as vulnerabilityLabel1, + v.label2 as vulnerabilityLabel2, + v.label3 as vulnerabilityLabel3, + v.label4 as vulnerabilityLabel4, + o.scope, + o.uuid as objectId + ') + ->where('ir.anr = :anr') + ->setParameter(':anr', $anr) + ->andWhere('ir.cacheMaxRisk > -1 OR ir.cacheTargetedRisk > -1') + ->innerJoin('ir.instance', 'i') + ->innerJoin('ir.threat', 't') + ->innerJoin('ir.vulnerability', 'v') + ->innerJoin('i.object', 'o') + ->getQuery() + ->getResult(); + } + + public function findRisksValuesForCartoStatsByAnr(Anr $anr, $riskValueField): array + { + return $this->getRepository()->createQueryBuilder('ir') + ->select([ + 'ir as instanceRisk', + 'ir.kindOfMeasure as treatment', + 'IDENTITY(ir.amv) as amv', + 'IDENTITY(ir.asset) as asset', + 'IDENTITY(ir.threat) as threat', + 'IDENTITY(ir.vulnerability) as vulnerability', + $riskValueField . ' as maximus', + 'i.c as ic', + 'i.i as ii', + 'i.d as id', + 'IDENTITY(i.object) as object', + 'm.c as mc', + 'm.i as mi', + 'm.a as ma', + 'o.scope', + ])->where('ir.anr = :anr') + ->setParameter(':anr', $anr) + ->andWhere($riskValueField . " != -1") + ->innerJoin('ir.instance', 'i') + ->innerJoin('ir.threat', 'm') + ->innerJoin('i.object', 'o') + ->getQuery() + ->getResult(); + } + + /** + * @return InstanceRisk[] + */ + public function findByAnrAndOrderByParams(Anr $anr, array $orderBy = []): array + { + $queryBuilder = $this->getRepository()->createQueryBuilder('ir') + ->innerJoin('ir.instance', 'i') + ->innerJoin('ir.threat', 't') + ->innerJoin('ir.vulnerability', 'v') + ->innerJoin('i.object', 'o') + ->where('ir.anr = :anr') + ->setParameter('anr', $anr); + + foreach ($orderBy as $fieldName => $order) { + $queryBuilder->addOrderBy($fieldName, $order); + } + + return $queryBuilder->getQuery()->getResult(); + } + + /** + * @return InstanceRisk[] + */ + public function findByAnrAndThreatExcludeLocallySet( + Anr $anr, + Threat $threat, + bool $excludeLocallySetThreatRates + ): array { + $queryBuilder = $this->getRepository()->createQueryBuilder('ir') + ->innerJoin('ir.threat', 't') + ->where('ir.anr = :anr') + ->andWhere('t.uuid = :threat_uuid') + ->andWhere('t.anr = :anr') + ->setParameter('anr', $anr) + ->setParameter('threat_uuid', $threat->getUuid()); + if ($excludeLocallySetThreatRates) { + $queryBuilder->andWhere('ir.isThreatRateNotSetOrModifiedExternally = 1'); + } + + return $queryBuilder->getQuery()->getResult(); + } + + public function existsInAnrWithInstanceThreatAndVulnerability( + Instance $instance, + Threat $threat, + Vulnerability $vulnerability + ): bool { + return (bool)$this->getRepository()->createQueryBuilder('ir') + ->innerJoin('ir.threat', 't') + ->innerJoin('ir.vulnerability', 'v') + ->where('ir.anr = :anr') + ->andWhere('ir.instance = :instance') + ->andWhere('t.uuid = :threat_uuid') + ->andWhere('t.anr = :anr') + ->andWhere('v.uuid = :vulnerability_uuid') + ->andWhere('v.anr = :anr') + ->setParameter('anr', $instance->getAnr()) + ->setParameter('instance', $instance) + ->setParameter('threat_uuid', $threat->getUuid()) + ->setParameter('vulnerability_uuid', $vulnerability->getUuid()) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT); + } + + /** + * @return InstanceRisk[] + */ + public function findSiblingSpecificInstanceRisks(InstanceRisk $instanceRisk): array + { + return $this->getRepository()->createQueryBuilder('ir') + ->innerJoin('ir.asset', 'a') + ->innerJoin('ir.threat', 't') + ->innerJoin('ir.vulnerability', 'v') + ->where('ir.anr = :anr') + ->andWhere('a.uuid = :asset_uuid') + ->andWhere('a.anr = :anr') + ->andWhere('t.uuid = :threat_uuid') + ->andWhere('t.anr = :anr') + ->andWhere('v.uuid = :vulnerability_uuid') + ->andWhere('v.anr = :anr') + ->andWhere('ir.id != ' . $instanceRisk->getId()) + ->andWhere('ir.specific = 1') + ->setParameter('anr', $instanceRisk->getAnr()) + ->setParameter('asset_uuid', $instanceRisk->getAsset()->getUuid()) + ->setParameter('threat_uuid', $instanceRisk->getThreat()->getUuid()) + ->setParameter('vulnerability_uuid', $instanceRisk->getVulnerability()->getUuid()) + ->getQuery() + ->getResult(); + } +} diff --git a/src/Model/Table/InstanceTable.php b/src/Table/InstanceTable.php similarity index 50% rename from src/Model/Table/InstanceTable.php rename to src/Table/InstanceTable.php index 48b92884..6a4c706c 100755 --- a/src/Model/Table/InstanceTable.php +++ b/src/Table/InstanceTable.php @@ -1,35 +1,27 @@ -entityClass = Instance::class; + parent::__construct($entityManager, $entityName); } /** @@ -39,10 +31,10 @@ public function findByAnrAndObject(AnrSuperClass $anr, ObjectSuperClass $object) { return $this->getRepository() ->createQueryBuilder('i') - ->innerJoin('i.object', 'obj') + ->innerJoin('i.object', 'o') ->where('i.anr = :anr') - ->andWhere('obj.uuid = :objUuid') - ->andWhere('obj.anr = :objAnr') + ->andWhere('o.uuid = :objUuid') + ->andWhere('o.anr = :objAnr') ->setParameter('anr', $anr) ->setParameter('objUuid', $object->getUuid()) ->setParameter('objAnr', $object->getAnr()) @@ -50,31 +42,14 @@ public function findByAnrAndObject(AnrSuperClass $anr, ObjectSuperClass $object) ->getResult(); } - /** - * @return Instance[] - */ - public function findByAnrAndAsset(Anr $anr, Asset $asset): array - { - return $this->getRepository() - ->createQueryBuilder('i') - ->innerJoin('i.asset', 'a') - ->where('i.anr = :anr') - ->andWhere('a.uuid = :assetUuid') - ->andWhere('a.anr = :anr') - ->setParameter('anr', $anr) - ->setParameter('assetUuid', $asset->getUuid()) - ->getQuery() - ->getResult(); - } - /** * @return Instance[] */ public function findByAnrAssetAndObjectExcludeInstance( - AnrSuperClass $anr, - AssetSuperClass $asset, - ObjectSuperClass $object, - InstanceSuperClass $instanceToExclude + Anr $anr, + Asset $asset, + MonarcObject $object, + Instance $instanceToExclude ): array { return $this->getRepository() ->createQueryBuilder('i') @@ -96,23 +71,6 @@ public function findByAnrAssetAndObjectExcludeInstance( ->getResult(); } - public function getMaxPositionByAnrAndParent(AnrSuperClass $anr, ?InstanceSuperClass $parentInstance = null): int - { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('i') - ->select('MAX(i.position)') - ->where('i.anr = :anr') - ->setParameter('anr', $anr); - - if ($parentInstance !== null) { - $queryBuilder - ->andWhere('i.parent = :parent') - ->setParameter('parent', $parentInstance); - } - - return (int)$queryBuilder->getQuery()->getSingleScalarResult(); - } - public function countByAnrIdFromDate(int $anrId, DateTime $fromDate): int { return (int)$this->getRepository()->createQueryBuilder('i') @@ -124,4 +82,55 @@ public function countByAnrIdFromDate(int $anrId, DateTime $fromDate): int ->getQuery() ->getSingleScalarResult(); } + + /** + * @return Instance[] + */ + public function findGlobalSiblingsByAnrAndInstance(Anr $anr, Instance $instance): array + { + return $this->getRepository() + ->createQueryBuilder('i') + ->innerJoin('i.object', 'o') + ->where('i.anr = :anr') + ->andWhere('o.uuid = :object_uuid') + ->andWhere('o.anr = :anr') + ->andWhere('i.id != :id') + ->andWhere('o.scope = ' . ObjectSuperClass::SCOPE_GLOBAL) + ->setParameter('anr', $anr) + ->setParameter('id', $instance->getId()) + ->setParameter('object_uuid', $instance->getObject()->getUuid()) + ->getQuery() + ->getResult(); + } + + /** + * @return Instance[] + */ + public function findInstancesByAnrWithEvaluationAndNotInheritedOrderBy(Anr $anr, array $orderBy = []): array + { + $queryBuilder = $this->getRepository()->createQueryBuilder('i'); + + $queryBuilder + ->where('i.anr = :anr') + ->andWhere($queryBuilder->expr()->orX( + $queryBuilder->expr()->andX( + $queryBuilder->expr()->gt('i.c', -1), + $queryBuilder->expr()->eq('i.ch', 0), + ), + $queryBuilder->expr()->andX( + $queryBuilder->expr()->gt('i.i', -1), + $queryBuilder->expr()->eq('i.ih', 0), + ), + $queryBuilder->expr()->andX( + $queryBuilder->expr()->gt('i.d', -1), + $queryBuilder->expr()->eq('i.dh', 0), + ) + ))->setParameter('anr', $anr); + + foreach ($orderBy as $fieldName => $order) { + $queryBuilder->addOrderBy($fieldName, $order); + } + + return $queryBuilder->getQuery()->getResult(); + } } diff --git a/src/Table/MeasureTable.php b/src/Table/MeasureTable.php new file mode 100755 index 00000000..5ccfbdd1 --- /dev/null +++ b/src/Table/MeasureTable.php @@ -0,0 +1,38 @@ +getRepository()->createQueryBuilder('m') + ->innerJoin('m.referential', 'r') + ->where('m.anr = :anr') + ->andWhere('r.uuid = :referentialUuid') + ->andWhere('r.anr = :anr') + ->setParameter('referentialUuid', $referentialUuid) + ->setParameter('anr', $anr) + ->orderBy('m.code') + ->getQuery() + ->getResult(); + } +} diff --git a/src/Table/MonarcObjectTable.php b/src/Table/MonarcObjectTable.php new file mode 100755 index 00000000..9e7abbc3 --- /dev/null +++ b/src/Table/MonarcObjectTable.php @@ -0,0 +1,81 @@ +getRepository()->createQueryBuilder('o') + ->innerJoin('o.asset', 'a') + ->where('o.anr = :anr') + ->andWhere('a.uuid = :assetUuid') + ->andWhere('a.anr = :assetAnr') + ->andWhere('o.' . $nameKey . ' = :name') + ->andWhere('o.scope = :scope') + ->andWhere('o.category = :category') + ->setParameter('anr', $anr) + ->setParameter('assetUuid', $asset->getUuid()) + ->setParameter('assetAnr', $anr) + ->setParameter('name', $nameValue) + ->setParameter('scope', $scope) + ->setParameter('category', $category) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + public function findOneByAnrAndName(Anr $anr, string $nameKey, string $nameValue): ?MonarcObject + { + return $this->getRepository()->createQueryBuilder('o') + ->where('o.anr = :anr') + ->andWhere('o.' . $nameKey . ' = :name') + ->setParameter('anr', $anr) + ->setParameter('name', $nameValue) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + /** + * @return MonarcObject[] + */ + public function findGlobalObjectsByAnr(Anr $anr): array + { + return $this->getRepository()->createQueryBuilder('o') + ->where('o.anr = :anr') + ->andWhere('o.scope = ' . ObjectSuperClass::SCOPE_GLOBAL) + ->setParameter('anr', $anr) + ->getQuery() + ->getResult(); + } +} diff --git a/src/Model/Table/ObjectCategoryTable.php b/src/Table/ObjectCategoryTable.php similarity index 57% rename from src/Model/Table/ObjectCategoryTable.php rename to src/Table/ObjectCategoryTable.php index 25ec85e3..fc969335 100755 --- a/src/Model/Table/ObjectCategoryTable.php +++ b/src/Table/ObjectCategoryTable.php @@ -1,30 +1,36 @@ -entityClass = ObjectCategory::class; + /** + * @return ObjectCategory[] + */ + public function findRootCategoriesByAnrOrderedByPosition(Anr $anr): array + { + return $this->getRepository()->createQueryBuilder('oc') + ->where('oc.anr = :anr') + ->andWhere('oc.parent IS NULL') + ->setParameter('anr', $anr) + ->addOrderBy('oc.position') + ->getQuery() + ->getResult(); } public function findByAnrParentAndLabel( @@ -33,8 +39,7 @@ public function findByAnrParentAndLabel( string $labelKey, string $labelValue ): ?ObjectCategory { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('oc') + $queryBuilder = $this->getRepository()->createQueryBuilder('oc') ->where('oc.anr = :anr') ->setParameter('anr', $anr); @@ -54,8 +59,7 @@ public function findByAnrParentAndLabel( public function findMaxPositionByAnrAndParent(Anr $anr, ?ObjectCategory $parentObjectCategory): int { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('oc') + $queryBuilder = $this->getRepository()->createQueryBuilder('oc') ->select('MAX(oc.position)') ->where('oc.anr = :anr') ->setParameter('anr', $anr); @@ -73,13 +77,4 @@ public function findMaxPositionByAnrAndParent(Anr $anr, ?ObjectCategory $parentO ->getQuery() ->getSingleScalarResult(); } - - public function saveEntity(ObjectCategorySuperClass $objectCategory, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($objectCategory); - if ($flushAll) { - $em->flush(); - } - } } diff --git a/src/Table/ObjectObjectTable.php b/src/Table/ObjectObjectTable.php new file mode 100755 index 00000000..15ee4af7 --- /dev/null +++ b/src/Table/ObjectObjectTable.php @@ -0,0 +1,63 @@ +getRepository()->createQueryBuilder('oo') + ->innerJoin('oo.parent', 'parent') + ->where('parent.uuid = :parentUuid') + ->andWhere('parent.anr = :anr') + ->setParameter('parentUuid', $object->getUuid()) + ->setParameter('anr', $object->getAnr()) + ->getQuery() + ->getResult(); + + if (!empty($childrenObjectsLinks)) { + foreach ($childrenObjectsLinks as $childObjectLink) { + $object->removeChildLink($childObjectLink); + $this->entityManager->remove($childObjectLink); + } + if ($saveInDb) { + $this->flush(); + } + } + } + + public function findByParentObjectAndPosition(MonarcObject $parentObject, int $position): ?ObjectObject + { + return $this->getRepository()->createQueryBuilder('oo') + ->innerJoin('oo.parent', 'parent') + ->where('parent.uuid = :parentUuid') + ->andWhere('parent.anr = :anr') + ->andWhere('oo.position = :position') + ->setParameter('parentUuid', $parentObject->getUuid()) + ->setParameter('anr', $parentObject->getAnr()) + ->setParameter('position', $position) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Model/Table/OperationalInstanceRiskScaleTable.php b/src/Table/OperationalInstanceRiskScaleTable.php similarity index 65% rename from src/Model/Table/OperationalInstanceRiskScaleTable.php rename to src/Table/OperationalInstanceRiskScaleTable.php index ef0d485c..e74aac98 100644 --- a/src/Model/Table/OperationalInstanceRiskScaleTable.php +++ b/src/Table/OperationalInstanceRiskScaleTable.php @@ -1,16 +1,17 @@ getRepository()->createQueryBuilder('oirs'); - $result = $queryBuilder + + return $queryBuilder ->where('oirs.anr = :anr') ->andWhere($queryBuilder->expr()->orX( $queryBuilder->expr()->neq('oirs.brutValue', -1), @@ -32,8 +34,6 @@ public function isRisksEvaluationStartedForAnr(Anr $anr): bool ->setParameter('anr', $anr) ->setMaxResults(1) ->getQuery() - ->getOneOrNullResult(); - - return $result !== null; + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT) !== null; } } diff --git a/src/Model/Table/OperationalRiskScaleCommentTable.php b/src/Table/OperationalRiskScaleCommentTable.php similarity index 62% rename from src/Model/Table/OperationalRiskScaleCommentTable.php rename to src/Table/OperationalRiskScaleCommentTable.php index 539f702e..8dd7a83c 100644 --- a/src/Model/Table/OperationalRiskScaleCommentTable.php +++ b/src/Table/OperationalRiskScaleCommentTable.php @@ -1,15 +1,15 @@ getRepository()->createQueryBuilder('rh') + ->where( + ($instanceRisk instanceof InstanceRisk ? 'rh.instanceRisk' : 'rh.instanceRiskOp') . ' = :instanceRisk' + ) + ->setParameter('instanceRisk', $instanceRisk); + + foreach ($orderParams as $param => $direction) { + $queryBuilder->addOrderBy('rh.' . $param, $direction); + } + + return $queryBuilder->getQuery()->getResult(); + } +} diff --git a/src/Model/Table/RecommandationRiskTable.php b/src/Table/RecommendationRiskTable.php similarity index 50% rename from src/Model/Table/RecommandationRiskTable.php rename to src/Table/RecommendationRiskTable.php index e594d945..22e88ad8 100755 --- a/src/Model/Table/RecommandationRiskTable.php +++ b/src/Table/RecommendationRiskTable.php @@ -1,55 +1,39 @@ -getRepository()->find($recommendationRiskId); - if ($recommendationRisk === null) { - throw new EntityNotFoundException(sprintf('Anr with id "%d" was not found', $recommendationRiskId)); - } - - return $recommendationRisk; + parent::__construct($entityManager, $entityName); } /** - * @return RecommandationRisk[] + * @return RecommendationRisk[] */ - public function findByAnr(AnrSuperClass $anr, array $order = [], bool $excludeNotTreated = true) - { - $queryBuilder = $this->getRepository() - ->createQueryBuilder('rr') - ->innerJoin('rr.recommandation', 'r') + public function findByAnrOrderByAndCanExcludeNotTreated( + AnrSuperClass $anr, + array $order = [], + bool $excludeNotTreated = true + ): array { + $queryBuilder = $this->getRepository()->createQueryBuilder('rr') + ->innerJoin('rr.recommendation', 'r') ->andWhere('rr.anr = :anr') ->setParameter('anr', $anr); @@ -69,28 +53,12 @@ public function findByAnr(AnrSuperClass $anr, array $order = [], bool $excludeNo ->getResult(); } - /** - * @return RecommandationRisk[] - */ - public function findByAnrAndInstanceRisk(AnrSuperClass $anr, InstanceRisk $instanceRisk) - { - return $this->getRepository() - ->createQueryBuilder('rr') - ->where('rr.anr = :anr') - ->andWhere('rr.instanceRisk = :instanceRisk') - ->setParameter('anr', $anr) - ->setParameter('instanceRisk', $instanceRisk) - ->getQuery() - ->getResult(); - } - public function findByInstanceRiskAndRecommendation( InstanceRisk $instanceRisk, - Recommandation $recommendation - ): ?RecommandationRisk { - return $this->getRepository() - ->createQueryBuilder('rr') - ->innerJoin('rr.recommandation', 'r') + Recommendation $recommendation + ): ?RecommendationRisk { + return $this->getRepository()->createQueryBuilder('rr') + ->innerJoin('rr.recommendation', 'r') ->where('rr.instanceRisk = :instanceRisk') ->andWhere('r.uuid = :recommendationUuid') ->andWhere('r.anr = :recommendationAnr') @@ -103,28 +71,12 @@ public function findByInstanceRiskAndRecommendation( } /** - * @return RecommandationRisk[] - */ - public function findByAnrAndOperationalInstanceRisk(AnrSuperClass $anr, InstanceRiskOp $instanceRiskOp) - { - return $this->getRepository() - ->createQueryBuilder('rr') - ->where('rr.anr = :anr') - ->andWhere('rr.instanceRiskOp = :instance_risk_op') - ->setParameter('anr', $anr) - ->setParameter('instance_risk_op', $instanceRiskOp) - ->getQuery() - ->getResult(); - } - - /** - * @return RecommandationRisk[] + * @return RecommendationRisk[] */ - public function findAllLinkedByRecommendationGlobalObjectAndAmv(RecommandationRisk $recommendationRisk) + public function findAllLinkedByRecommendationGlobalObjectAndAmv(RecommendationRisk $recommendationRisk): array { - return $this->getRepository() - ->createQueryBuilder('rr') - ->innerJoin('rr.recommandation', 'r') + return $this->getRepository()->createQueryBuilder('rr') + ->innerJoin('rr.recommendation', 'r') ->innerJoin('rr.globalObject', 'go') ->innerJoin('rr.asset', 'a') ->innerJoin('rr.threat', 't') @@ -141,8 +93,8 @@ public function findAllLinkedByRecommendationGlobalObjectAndAmv(RecommandationRi ->andWhere('v.uuid = :vulnerability_uuid') ->andWhere('v.anr = :vulnerability_anr') ->setParameter('anr', $recommendationRisk->getAnr()) - ->setParameter('recommendation_uuid', $recommendationRisk->getRecommandation()->getUuid()) - ->setParameter('recommendation_anr', $recommendationRisk->getRecommandation()->getAnr()) + ->setParameter('recommendation_uuid', $recommendationRisk->getRecommendation()->getUuid()) + ->setParameter('recommendation_anr', $recommendationRisk->getRecommendation()->getAnr()) ->setParameter('global_object_uuid', $recommendationRisk->getGlobalObject()->getUuid()) ->setParameter('global_object_anr', $recommendationRisk->getGlobalObject()->getAnr()) ->setParameter('asset_uuid', $recommendationRisk->getAsset()->getUuid()) @@ -155,21 +107,41 @@ public function findAllLinkedByRecommendationGlobalObjectAndAmv(RecommandationRi ->getResult(); } - public function deleteEntity(RecommandationRisk $recommendationRisk, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->remove($recommendationRisk); - if ($flush) { - $em->flush(); - } + public function existsWithAnrRecommendationAndInstanceRisk( + Anr $anr, + Recommendation $recommendation, + InstanceRisk $instanceRisk + ): bool { + return (bool)$this->getRepository()->createQueryBuilder('rr') + ->innerJoin('rr.recommendation', 'r') + ->where('rr.anr = :anr') + ->andWhere('r.uuid = :recommendation_uuid') + ->andWhere('r.anr = :anr') + ->andWhere('rr.instanceRisk = :instanceRisk') + ->setParameter('anr', $anr) + ->setParameter('recommendation_uuid', $recommendation->getUuid()) + ->setParameter('instanceRisk', $instanceRisk) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT); } - public function saveEntity(RecommandationRisk $recommendationRisk, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($recommendationRisk); - if ($flush) { - $em->flush(); - } + public function existsWithAnrRecommendationAndInstanceRiskOp( + Anr $anr, + Recommendation $recommendation, + InstanceRiskOp $instanceRiskOp + ): bool { + return (bool)$this->getRepository()->createQueryBuilder('rr') + ->innerJoin('rr.recommendation', 'r') + ->where('rr.anr = :anr') + ->andWhere('r.uuid = :recommendation_uuid') + ->andWhere('r.anr = :anr') + ->andWhere('rr.instanceRiskOp = :instanceRiskOp') + ->setParameter('anr', $anr) + ->setParameter('recommendation_uuid', $recommendation->getUuid()) + ->setParameter('instanceRiskOp', $instanceRiskOp) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT); } } diff --git a/src/Table/RecommendationSetTable.php b/src/Table/RecommendationSetTable.php new file mode 100644 index 00000000..7744ad2c --- /dev/null +++ b/src/Table/RecommendationSetTable.php @@ -0,0 +1,20 @@ +getRepository() - ->createQueryBuilder('r') - ->select('MAX(r.position)') - ->where('r.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getSingleScalarResult(); + parent::__construct($entityManager, $entityName); } /** - * @return Recommandation[] + * @return Recommendation[] */ - public function findByAnrWithEmptyPosition(Anr $anr) + public function findByAnrWithEmptyPosition(Anr $anr): array { return $this->getRepository() ->createQueryBuilder('r') @@ -53,13 +43,13 @@ public function findByAnrWithEmptyPosition(Anr $anr) } /** - * @return Recommandation[] + * @return Recommendation[] */ public function findLinkedWithRisksByAnrWithSpecifiedImportanceAndPositionAndExcludeRecommendations( AnrSuperClass $anr, array $excludeRecommendations = [], array $order = [] - ) { + ): array { $queryBuilder = $this->getRepository() ->createQueryBuilder('r') ->innerJoin('r.recommendationRisks', 'rr') @@ -84,51 +74,14 @@ public function findLinkedWithRisksByAnrWithSpecifiedImportanceAndPositionAndExc ->getResult(); } - /** - * @return Recommandation[] - */ - public function findByAnr(AnrSuperClass $anr): array - { - return $this->getRepository() - ->createQueryBuilder('r') - ->where('r.anr = :anr') - ->setParameter('anr', $anr) - ->getQuery() - ->getResult(); - } - - /** - * @throws EntityNotFoundException - */ - public function findByAnrAndUuid(AnrSuperClass $anr, string $uuid): Recommandation - { - $recommendation = $this->getRepository() - ->createQueryBuilder('r') - ->where('r.anr = :anr') - ->andWhere('r.uuid = :uuid') - ->setParameter('anr', $anr) - ->setParameter('uuid', $uuid) - ->setMaxResults(1) - ->getQuery() - ->getOneOrNullResult(); - - if ($recommendation === null) { - throw new EntityNotFoundException( - sprintf('Recommendation with anr ID "%d" and uuid "%s" has not been found.', $anr->getId(), $uuid) - ); - } - - return $recommendation; - } - public function findByAnrCodeAndRecommendationSet( AnrSuperClass $anr, string $code, - RecommandationSet $recommendationSet - ): ?Recommandation { + RecommendationSet $recommendationSet + ): ?Recommendation { return $this->getRepository() ->createQueryBuilder('r') - ->innerJoin('r.recommandationSet', 'rs') + ->innerJoin('r.recommendationSet', 'rs') ->where('r.anr = :anr') ->andWhere('r.code = :code') ->andWhere('rs.uuid = :recommendation_set_uuid') @@ -145,9 +98,9 @@ public function findByAnrCodeAndRecommendationSet( /** * Returns list of recommendations which are unlinked with risks and position is not 0. * - * @return Recommandation[] + * @return Recommendation[] */ - public function findUnlinkedWithNotEmptyPositionByAnr(AnrSuperClass $anr) + public function findUnlinkedWithNotEmptyPositionByAnr(AnrSuperClass $anr): array { $queryBuilderLinked = $this->getRepository() ->createQueryBuilder('rec') @@ -168,22 +121,4 @@ public function findUnlinkedWithNotEmptyPositionByAnr(AnrSuperClass $anr) ->getQuery() ->getResult(); } - - public function saveEntity(Recommandation $recommendation, bool $flushAll = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->persist($recommendation); - if ($flushAll) { - $em->flush(); - } - } - - public function deleteEntity(Recommandation $recommendation, bool $flush = true): void - { - $em = $this->getDb()->getEntityManager(); - $em->remove($recommendation); - if ($flush) { - $em->flush(); - } - } } diff --git a/src/Table/ReferentialTable.php b/src/Table/ReferentialTable.php new file mode 100644 index 00000000..8695200f --- /dev/null +++ b/src/Table/ReferentialTable.php @@ -0,0 +1,21 @@ +getRepository()->createQueryBuilder('rr') + ->where('rr.anr = :anr') + ->andWhere('rr.code = :code') + ->setParameter('anr', $anr) + ->setParameter('code', $code) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Table/RolfTagTable.php b/src/Table/RolfTagTable.php new file mode 100755 index 00000000..58691775 --- /dev/null +++ b/src/Table/RolfTagTable.php @@ -0,0 +1,24 @@ +getRepository()->findAll(); + } + + /** + * @return Snapshot[] + */ + public function findByAnrReferenceAndOrderBy(Anr $anr, array $order): array + { + $queryBuilder = $this->getRepository()->createQueryBuilder('s') + ->where('s.anrReference = :anr') + ->setParameter('anr', $anr); + + foreach ($order as $field => $direction) { + $queryBuilder->addOrderBy('s.' . $field, $direction); + } + + return $queryBuilder->getQuery()->getResult(); + } +} diff --git a/src/Table/SoaCategoryTable.php b/src/Table/SoaCategoryTable.php new file mode 100755 index 00000000..d6cf3ef3 --- /dev/null +++ b/src/Table/SoaCategoryTable.php @@ -0,0 +1,20 @@ +getRepository()->createQueryBuilder('s') + ->innerJoin('s.measure', 'm') + ->where('s.anr = :anr') + ->andWhere('m.category = :category') + ->setParameter('anr', $anr) + ->setParameter('category', $soaCategory); + + foreach ($order as $filed => $direction) { + $queryBuilder->addOrderBy($filed, $direction); + } + + return $queryBuilder->getQuery()->getResult(); + } + + public function findByAnrAndMeasureUuid(Entity\Anr $anr, string $measureUuid): ?Entity\Soa + { + return $this->getRepository()->createQueryBuilder('s') + ->innerJoin('s.measure', 'm') + ->where('s.anr = :anr') + ->andWhere('m.uuid = :measure_uuid') + ->andWhere('m.anr = :anr') + ->setParameter('anr', $anr) + ->setParameter('measure_uuid', $measureUuid) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } + + /** + * @return Entity\Soa[] + */ + public function findByAnrWithNotEmptySoaScaleComments(Entity\Anr $anr): array + { + return $this->getRepository()->createQueryBuilder('s') + ->where('s.anr = :anr') + ->andWhere('s.soaScaleComment IS NOT NULL') + ->setParameter('anr', $anr) + ->getQuery() + ->getResult(); + } +} diff --git a/src/Table/SystemMessageTable.php b/src/Table/SystemMessageTable.php new file mode 100755 index 00000000..55460b69 --- /dev/null +++ b/src/Table/SystemMessageTable.php @@ -0,0 +1,51 @@ +getRepository()->createQueryBuilder('sm') + ->where('sm.user = :user') + ->andWhere('sm.status = ' . SystemMessage::STATUS_ACTIVE) + ->setParameter('user', $user) + ->getQuery() + ->getResult(); + } + + public function findByIdAndUser(int $id, User $user): SystemMessage + { + $systemMessage = $this->getRepository()->createQueryBuilder('sm') + ->where('sm.id = :id') + ->andWhere('sm.user = :user') + ->setParameter('id', $id) + ->setParameter('user', $user) + ->getQuery() + ->getOneOrNullResult(); + if ($systemMessage === null) { + throw EntityNotFoundException::fromClassNameAndIdentifier(SystemMessage::class, [$id]); + } + + return $systemMessage; + } +} diff --git a/src/Table/ThemeTable.php b/src/Table/ThemeTable.php new file mode 100755 index 00000000..87003b3b --- /dev/null +++ b/src/Table/ThemeTable.php @@ -0,0 +1,21 @@ +getRepository()->createQueryBuilder('t') + ->where('t.anr = :anr') + ->setParameter(':anr', $anr) + ->andWhere('t.qualification != -1') + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(AbstractQuery::HYDRATE_SIMPLEOBJECT) !== null; + } +} diff --git a/src/Table/UserAnrTable.php b/src/Table/UserAnrTable.php new file mode 100755 index 00000000..1ef4db44 --- /dev/null +++ b/src/Table/UserAnrTable.php @@ -0,0 +1,34 @@ +getRepository()->createQueryBuilder('ua') + ->where('ua.anr = :anr') + ->andWhere('ua.user = :user') + ->setParameter('anr', $anr) + ->setParameter('user', $user) + ->setMaxResults(1) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Table/UserTable.php b/src/Table/UserTable.php new file mode 100755 index 00000000..f0661b30 --- /dev/null +++ b/src/Table/UserTable.php @@ -0,0 +1,20 @@ +getOptions()['anrTable']; - $anrId = (int)($value['id'] ?? $value); + $anrTable = $this->getOption('anrTable'); try { - $anrTable->findById($anrId); - } catch (EntityNotFoundException $e) { + $anrTable->findById((int)($value['id'] ?? $value)); + } catch (EntityNotFoundException) { $this->error(self::ANR_DOES_NOT_EXIST, $value); return false; diff --git a/src/Validator/FieldValidator/IsModelActiveValidator.php b/src/Validator/FieldValidator/IsModelActiveValidator.php new file mode 100644 index 00000000..b6cd8c80 --- /dev/null +++ b/src/Validator/FieldValidator/IsModelActiveValidator.php @@ -0,0 +1,45 @@ + 'Model ID parameter is missing.', + self::MODEL_IS_INACTIVE => 'Model "%value%" is inactive.', + ]; + + public function isValid($value) + { + if (empty($value)) { + $this->error(self::MISSING_MODEL_ID); + + return false; + } + + /** @var ModelTable $modelTable */ + $modelTable = $this->getOption('modelTable'); + /** @var Model $model */ + $model = $modelTable->findById($value); + if (!$model->isActive()) { + $this->error(self::MISSING_MODEL_ID, $model->getLabel($this->getOption('languageIndex'))); + + return false; + } + + return true; + } +} + diff --git a/src/Validator/InputValidator/AbstractMonarcInputValidator.php b/src/Validator/InputValidator/AbstractMonarcInputValidator.php deleted file mode 100644 index c9002c20..00000000 --- a/src/Validator/InputValidator/AbstractMonarcInputValidator.php +++ /dev/null @@ -1,44 +0,0 @@ -inputFilter = $inputFilter; - - $this->initRules(); - } - - abstract protected function getRules(): array; - - private function initRules(): void - { - foreach ($this->getRules() as $rule) { - $this->inputFilter->add($rule); - } - } - - public function isValid(array $data): bool - { - $this->inputFilter->setData($data); - - return $this->inputFilter->isValid(); - } - - public function getErrorMessages(): array - { - return $this->inputFilter->getMessages(); - } - - public function getValidData(): array - { - return $this->inputFilter->getValues(); - } -} diff --git a/src/Validator/InputValidator/Anr/CreateAnrDataInputValidator.php b/src/Validator/InputValidator/Anr/CreateAnrDataInputValidator.php new file mode 100644 index 00000000..e511d734 --- /dev/null +++ b/src/Validator/InputValidator/Anr/CreateAnrDataInputValidator.php @@ -0,0 +1,104 @@ +modelTable = $modelTable; + + parent::__construct($config, $translator); + } + + protected function getRules(): array + { + return [ + [ + 'name' => 'label', + 'required' => true, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 255, + ] + ], + ], + ], + [ + 'name' => 'description', + 'required' => false, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + ], + [ + 'name' => 'model', + 'required' => true, + 'allow_empty' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => IsModelActiveValidator::class, + 'options' => [ + 'modelTable' => $this->modelTable, + 'languageIndex' => $this->defaultLanguageIndex, + ], + ] + ], + ], + [ + 'name' => 'language', + 'required' => true, + 'allow_empty' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => $this->systemLanguageIndexes, + ] + ] + ], + ], + [ + 'name' => 'referentials', + 'required' => false, + 'filters' => [], + 'validators' => [], + ] + ]; + } +} diff --git a/src/Validator/InputValidator/InstanceRisk/PostSpecificInstanceRiskDataInputValidator.php b/src/Validator/InputValidator/InstanceRisk/PostSpecificInstanceRiskDataInputValidator.php new file mode 100644 index 00000000..acc60baf --- /dev/null +++ b/src/Validator/InputValidator/InstanceRisk/PostSpecificInstanceRiskDataInputValidator.php @@ -0,0 +1,59 @@ + 'instance', + 'required' => true, + 'allow_empty' => false, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [], + ], + [ + 'name' => 'threat', + 'required' => true, + 'allow_empty' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'vulnerability', + 'required' => true, + 'allow_empty' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/InstanceRisk/UpdateInstanceRiskDataInputValidator.php b/src/Validator/InputValidator/InstanceRisk/UpdateInstanceRiskDataInputValidator.php new file mode 100644 index 00000000..505a8b09 --- /dev/null +++ b/src/Validator/InputValidator/InstanceRisk/UpdateInstanceRiskDataInputValidator.php @@ -0,0 +1,52 @@ + 'owner', + 'required' => false, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + 'validators' => [], + ], + [ + 'name' => 'context', + 'required' => false, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + 'validators' => [], + ], + [ + 'name' => 'reductionAmount', + 'required' => false, + 'filters' => [ + [ + 'name' => ToInt::class, + ], + ], + 'validators' => [], + ], + ]); + } +} diff --git a/src/Validator/InputValidator/InstanceRiskOp/PostSpecificInstanceRiskOpDataInputValidator.php b/src/Validator/InputValidator/InstanceRiskOp/PostSpecificInstanceRiskOpDataInputValidator.php new file mode 100644 index 00000000..39e1dc7a --- /dev/null +++ b/src/Validator/InputValidator/InstanceRiskOp/PostSpecificInstanceRiskOpDataInputValidator.php @@ -0,0 +1,104 @@ +initialData['source']) + && (int)$this->initialData['source'] === AnrInstanceRiskOpService::CREATION_SOURCE_FROM_RISK; + + return [ + [ + 'name' => 'source', + 'required' => true, + 'allow_empty' => false, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => [ + AnrInstanceRiskOpService::CREATION_SOURCE_FROM_RISK, + AnrInstanceRiskOpService::CREATION_SOURCE_NEW_RISK, + ], + ] + ] + ], + ], + [ + 'name' => 'instance', + 'required' => true, + 'allow_empty' => false, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [], + ], + [ + 'name' => 'risk', + 'required' => $isSourceFromRisk, + 'allow_empty' => !$isSourceFromRisk, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [], + ], + [ + 'name' => 'code', + 'required' => !$isSourceFromRisk, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 100, + ] + ], + ], + ], + [ + 'name' => 'label', + 'required' => !$isSourceFromRisk, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 255, + ] + ], + ], + ], + [ + 'name' => 'description', + 'required' => !$isSourceFromRisk, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + ], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/InstanceRiskOp/UpdateInstanceRiskOpDataInputValidator.php b/src/Validator/InputValidator/InstanceRiskOp/UpdateInstanceRiskOpDataInputValidator.php new file mode 100644 index 00000000..85a50bc4 --- /dev/null +++ b/src/Validator/InputValidator/InstanceRiskOp/UpdateInstanceRiskOpDataInputValidator.php @@ -0,0 +1,42 @@ + 'owner', + 'required' => false, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + 'validators' => [], + ], + [ + 'name' => 'context', + 'required' => false, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + 'validators' => [], + ], + ]); + } +} diff --git a/src/Validator/InputValidator/Object/DuplicateObjectDataInputValidator.php b/src/Validator/InputValidator/Object/DuplicateObjectDataInputValidator.php new file mode 100644 index 00000000..a3cfe193 --- /dev/null +++ b/src/Validator/InputValidator/Object/DuplicateObjectDataInputValidator.php @@ -0,0 +1,34 @@ + 'id', + 'required' => true, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/Object/PostObjectDataInputValidator.php b/src/Validator/InputValidator/Object/PostObjectDataInputValidator.php new file mode 100644 index 00000000..2ce77b2a --- /dev/null +++ b/src/Validator/InputValidator/Object/PostObjectDataInputValidator.php @@ -0,0 +1,70 @@ +getLabelRule($this->defaultLanguageIndex), + $this->getNameRule($this->defaultLanguageIndex), + [ + 'name' => 'scope', + 'required' => true, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => [ObjectSuperClass::SCOPE_LOCAL, ObjectSuperClass::SCOPE_GLOBAL], + ] + ] + ], + ], + [ + 'name' => 'asset', + 'required' => true, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'category', + 'required' => true, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [], + ], + [ + 'name' => 'rolfTag', + 'required' => false, + 'allow_empty' => true, + 'filters' => [ + ['name' => 'ToInt'], + ], + 'validators' => [], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/Recommendation/PatchRecommendationDataInputValidator.php b/src/Validator/InputValidator/Recommendation/PatchRecommendationDataInputValidator.php new file mode 100644 index 00000000..5e814e94 --- /dev/null +++ b/src/Validator/InputValidator/Recommendation/PatchRecommendationDataInputValidator.php @@ -0,0 +1,191 @@ +initialData['recommendationSet']) && !empty($this->includeFilter['anr'])) { + $this->includeFilter['recommendationSet'] = [ + 'uuid' => $this->initialData['recommendationSet'], + 'anr' => $this->includeFilter['anr'], + ]; + } + + return [ + [ + 'name' => 'recommendationSet', + 'required' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'code', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 100, + ] + ], + [ + 'name' => UniqueCode::class, + 'options' => [ + 'uniqueCodeValidationTable' => $this->recommendationTable, + 'includeFilter' => $this->includeFilter, + 'excludeFilter' => $this->excludeFilter, + ], + ], + ], + ], + [ + 'name' => 'description', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + [ + 'name' => 'comment', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + [ + 'name' => 'duedate', + 'required' => false, + 'filters' => [ + ['name' => DateTimeFormatter::class], + ], + 'validators' => [], + ], + [ + 'name' => 'importance', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => array_keys(Recommendation::getImportances()), + ] + ], + ], + ], + [ + 'name' => 'implicitPosition', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => [ + PositionUpdatableServiceInterface::IMPLICIT_POSITION_START, + PositionUpdatableServiceInterface::IMPLICIT_POSITION_END, + PositionUpdatableServiceInterface::IMPLICIT_POSITION_AFTER, + ], + ], + ], + ], + ], + [ + 'name' => 'previous', + 'required' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'responsable', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 255, + ] + ], + ], + ], + [ + 'name' => 'status', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => [0, 1], + ], + ], + ], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/Recommendation/PostRecommendationDataInputValidator.php b/src/Validator/InputValidator/Recommendation/PostRecommendationDataInputValidator.php new file mode 100644 index 00000000..fb249e9c --- /dev/null +++ b/src/Validator/InputValidator/Recommendation/PostRecommendationDataInputValidator.php @@ -0,0 +1,205 @@ +initialData['recommendationSet']) && !empty($this->includeFilter['anr'])) { + $this->includeFilter['recommendationSet'] = [ + 'uuid' => $this->initialData['recommendationSet'], + 'anr' => $this->includeFilter['anr'], + ]; + } + + return [ + [ + 'name' => 'uuid', + 'required' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'recommendationSet', + 'required' => true, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'code', + 'required' => true, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 100, + ] + ], + [ + 'name' => UniqueCode::class, + 'options' => [ + 'uniqueCodeValidationTable' => $this->recommendationTable, + 'includeFilter' => $this->includeFilter, + 'excludeFilter' => $this->excludeFilter, + ], + ], + ], + ], + [ + 'name' => 'description', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + [ + 'name' => 'comment', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + [ + 'name' => 'duedate', + 'required' => false, + 'filters' => [ + ['name' => DateTimeFormatter::class], + ], + 'validators' => [], + ], + [ + 'name' => 'importance', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => array_keys(Recommendation::getImportances()), + ] + ], + ], + ], + [ + 'name' => 'implicitPosition', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => [ + PositionUpdatableServiceInterface::IMPLICIT_POSITION_START, + PositionUpdatableServiceInterface::IMPLICIT_POSITION_END, + PositionUpdatableServiceInterface::IMPLICIT_POSITION_AFTER, + ], + ], + ], + ], + ], + [ + 'name' => 'previous', + 'required' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'responsable', + 'required' => false, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 255, + ] + ], + ], + ], + [ + 'name' => 'status', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [ + [ + 'name' => InArray::class, + 'options' => [ + 'haystack' => [0, 1], + ], + ], + ], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/RecommendationRisk/PatchRecommendationRiskDataInputValidator.php b/src/Validator/InputValidator/RecommendationRisk/PatchRecommendationRiskDataInputValidator.php new file mode 100644 index 00000000..714459fe --- /dev/null +++ b/src/Validator/InputValidator/RecommendationRisk/PatchRecommendationRiskDataInputValidator.php @@ -0,0 +1,28 @@ + 'commentAfter', + 'required' => true, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/RecommendationRisk/PostRecommendationRiskDataInputValidator.php b/src/Validator/InputValidator/RecommendationRisk/PostRecommendationRiskDataInputValidator.php new file mode 100644 index 00000000..4397e194 --- /dev/null +++ b/src/Validator/InputValidator/RecommendationRisk/PostRecommendationRiskDataInputValidator.php @@ -0,0 +1,51 @@ + 'recommendation', + 'required' => true, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'instanceRisk', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [], + ], + [ + 'name' => 'instanceRiskOp', + 'required' => false, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/RecommendationRisk/ValidateRecommendationRiskDataInputValidator.php b/src/Validator/InputValidator/RecommendationRisk/ValidateRecommendationRiskDataInputValidator.php new file mode 100644 index 00000000..17727e63 --- /dev/null +++ b/src/Validator/InputValidator/RecommendationRisk/ValidateRecommendationRiskDataInputValidator.php @@ -0,0 +1,29 @@ + 'comment', + 'required' => true, + 'allow_empty' => true, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/RecommendationSet/PostRecommendationSetDataInputValidator.php b/src/Validator/InputValidator/RecommendationSet/PostRecommendationSetDataInputValidator.php new file mode 100644 index 00000000..94345426 --- /dev/null +++ b/src/Validator/InputValidator/RecommendationSet/PostRecommendationSetDataInputValidator.php @@ -0,0 +1,53 @@ + 'uuid', + 'required' => false, + 'filters' => [], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 36, + 'max' => 36, + ] + ], + ], + ], + [ + 'name' => 'label', + 'required' => true, + 'filters' => [ + [ + 'name' => StringTrim::class, + ], + ], + 'validators' => [ + [ + 'name' => StringLength::class, + 'options' => [ + 'min' => 1, + 'max' => 255, + ] + ], + ], + ], + ]; + } +} diff --git a/src/Validator/InputValidator/Threat/PostThreatDataInputValidator.php b/src/Validator/InputValidator/Threat/PostThreatDataInputValidator.php new file mode 100644 index 00000000..94fffdd2 --- /dev/null +++ b/src/Validator/InputValidator/Threat/PostThreatDataInputValidator.php @@ -0,0 +1,58 @@ + 'comment', + 'required' => false, + 'allow_empty' => true, + 'filters' => [ + ['name' => StringTrim::class], + ], + 'validators' => [], + ], + [ + 'name' => 'trend', + 'required' => false, + 'allow_empty' => true, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [], + ], + [ + 'name' => 'qualification', + 'required' => false, + 'allow_empty' => true, + 'filters' => [ + ['name' => ToInt::class], + ], + 'validators' => [], + ], + [ + 'name' => 'forceQualification', + 'required' => false, + 'allow_empty' => true, + 'filters' => [ + ['name' => Boolean::class], + ], + 'validators' => [], + ], + ]); + } +} diff --git a/src/Validator/InputValidator/User/CreateUserInputValidator.php b/src/Validator/InputValidator/User/CreateUserInputValidator.php deleted file mode 100644 index afa69b81..00000000 --- a/src/Validator/InputValidator/User/CreateUserInputValidator.php +++ /dev/null @@ -1,192 +0,0 @@ -availableLanguages = $config['languages']; - $this->userTable = $userTable; - $this->connectedUserService = $connectedUserService; - $this->anrTable = $anrTable; - - parent::__construct($inputFilter); - } - - protected function getRules(): array - { - return [ - [ - 'name' => 'firstname', - 'required' => true, - 'filters' => [ - [ - 'name' => StringTrim::class, - ], - ], - 'validators' => [ - [ - 'name' => StringLength::class, - 'options' => [ - 'min' => 1, - 'max' => 100, - ] - ], - ], - ], - [ - 'name' => 'lastname', - 'required' => true, - 'filters' => [ - [ - 'name' => StringTrim::class, - ], - ], - 'validators' => [ - [ - 'name' => StringLength::class, - 'options' => [ - 'min' => 1, - 'max' => 100, - ] - ], - ], - ], - [ - 'name' => 'password', - 'required' => false, - 'filters' => [ - [ - 'name' => StringTrim::class, - ], - ], - 'validators' => [ - [ - 'name' => StringLength::class, - 'options' => [ - 'min' => 9, - ] - ], - ], - ], - [ - 'name' => 'email', - 'required' => true, - 'filters' => [ - [ - 'name' => StringTrim::class, - ], - ], - 'validators' => [ - [ - 'name' => EmailAddress::class, - ], - [ - 'name' => UniqueEmail::class, - 'options' => [ - 'userTable' => $this->userTable, - 'currentUserId' => $this->connectedUserService->getConnectedUser()->getId(), - ], - // TODO: The following code requires the Db classes refactoring, also an issue with Laminas. - /* - 'name' => NoRecordExists::class, - 'options' => [ - 'adapter' => $this->userTable->getDb(), - 'table' => $this->userTable->getDb()->getEntityManager()->getClassMetadata(User::class)->getTableName(), - 'field' => 'email', - ], - 'messages' => [ - NoRecordExists::ERROR_RECORD_FOUND => 'This email is already used', - ], - */ - ], - ], - ], - [ - 'name' => 'role', - 'required' => true, - 'type' => ArrayInput::class, - 'validators' => [ - [ - 'name' => NotEmpty::class, - ], - [ - 'name' => Callback::class, - 'options' => [ - 'callback' => [$this, 'validateRoles'], - ], - ], - ], - ], - [ - 'name' => 'anrs', - 'required' => false, - 'type' => ArrayInput::class, - 'validators' => [ - [ - 'name' => AnrExistenceValidator::class, - 'options' => [ - 'anrTable' => $this->anrTable, - ], - ] - ], - ], - [ - 'name' => 'language', - 'allowEmpty' => true, - 'continueIfEmpty' => true, - 'required' => false, - 'filters' => [ - ['name' => 'ToInt'], - ], - 'validators' => [ - [ - 'name' => LanguageValidator::class, - 'options' => [ - 'availableLanguages' => $this->availableLanguages, - ] - ] - ], - ], - ]; - } - - public function validateRoles($value): bool - { - return in_array($value, UserRole::getAvailableRoles()); - } -} diff --git a/src/Validator/InputValidator/User/PostUserDataInputValidator.php b/src/Validator/InputValidator/User/PostUserDataInputValidator.php new file mode 100644 index 00000000..98498293 --- /dev/null +++ b/src/Validator/InputValidator/User/PostUserDataInputValidator.php @@ -0,0 +1,54 @@ +anrTable = $anrTable; + $this->userRoles = UserRole::getAvailableRoles(); + } + + protected function getRules(): array + { + return array_merge(parent::getRules(), [ + [ + 'name' => 'anrs', + 'required' => false, + 'type' => ArrayInput::class, + 'validators' => [ + [ + 'name' => AnrExistenceValidator::class, + 'options' => [ + 'anrTable' => $this->anrTable, + ], + ] + ], + ], + ]); + } +} diff --git a/view/layout/layout.phtml b/view/layout/layout.phtml index 0a465eae..86c3287b 100755 --- a/view/layout/layout.phtml +++ b/view/layout/layout.phtml @@ -87,11 +87,12 @@ ->appendFile('js/ClientPasswordForgottenCtrl.js') ->appendFile('js/ClientSnapshotService.js') ->appendFile('js/ClientInterviewService.js') - ->appendFile('js/ClientRecommandationService.js') + ->appendFile('js/ClientRecommendationService.js') ->appendFile('js/TreatmentPlanService.js') ->appendFile('js/ClientSoaService.js') ->appendFile('js/StatsService.js') ->appendFile('js/ClientSettingsCtrl.js') + ->appendFile('js/SystemMessageService.js') // ANR, but client-only ->appendFile('js/anr/AnrKbMgmtCtrl.js')