src/Controller/DashboardController.php line 108

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Company;
  4. use App\Entity\EmployeeReview;
  5. use App\Entity\Employees\Employee;
  6. use App\Entity\Employees\EmployeePosition;
  7. use App\Entity\Location;
  8. use App\Entity\QuadSettings;
  9. use App\Repository\UserPermissionRepository;
  10. use App\Service\Dashboard\PanelDataService;
  11. use App\Service\Dashboard\PieDataService;
  12. use App\Service\DashboardStatsService;
  13. use App\Service\PeriodService;
  14. use Doctrine\ORM\EntityManagerInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\Response;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. use Symfony\Component\Security\Core\Security;
  20. #[Route(path'/')]
  21. class DashboardController extends AbstractController
  22. {
  23.     /**
  24.      * @var EmployeeReview[]
  25.      */
  26.     private $allReviews;
  27.     /**
  28.      * @var Location[]
  29.      */
  30.     private $locations;
  31.     private $colorSets = [
  32.         => ['#ffffff''#b5b2b5''#7f7a7f''#534f55''#2f2c33''#040707'],
  33.         => ['#fddb00''#b89d31''#816f34''#544a2f''#2f2a25''#040707'],
  34.         => ['#f7941e''#b6702e''#82532f''#573b2c''#312423''#040707'],
  35.         => ['#4060ac''#3d5087''#344067''#292f4b''#1b1e31''#040707'],
  36.     ];
  37.     private $quads = [];
  38.     /**
  39.      * @var Security
  40.      */
  41.     private $security;
  42.     /**
  43.      * @var PieDataService
  44.      */
  45.     private $pieDataService;
  46.     /**
  47.      * @var PeriodService
  48.      */
  49.     private $periodService;
  50.     /**
  51.      * @var EntityManagerInterface
  52.      */
  53.     private $em;
  54.     /**
  55.      * @var DashboardStatsService
  56.      */
  57.     private $dashboardStats;
  58.     /**
  59.      * @var PanelDataService
  60.      */
  61.     private $panelDataService;
  62.     /**
  63.      * DashboardController constructor.
  64.      */
  65.     public function __construct(Security $securityPieDataService $pieDataServicePeriodService $periodServiceEntityManagerInterface $emDashboardStatsService $dashboardStatsPanelDataService $panelDataService)
  66.     {
  67.         $this->security $security;
  68.         $this->pieDataService $pieDataService;
  69.         $this->periodService $periodService;
  70.         /** @var QuadSettings[] $quadSettings */
  71.         $quadSettings $em->getRepository(QuadSettings::class)->findAll();
  72.         /** @var QuadSettings $quadSetting */
  73.         foreach ($quadSettings as $quadSetting) {
  74.             $this->quads[$quadSetting->getPositionNumber()] = $quadSetting->getName();
  75.         }
  76.         $this->em $em;
  77.         $this->dashboardStats $dashboardStats;
  78.         $this->panelDataService $panelDataService;
  79.     }
  80.     /**
  81.      * @param Request     $request
  82.      * @return Response
  83.      * @throws \Exception
  84.      */
  85.     #[Route(path'/review'name'review_test'methods: ['GET''POST'])]
  86.     public function review(Request $request): Response
  87.     {
  88.         $companyInfo $this->getCompanyInfo();
  89.         $company $companyInfo;
  90.         return $this->render('dashboard/review.html.twig', [
  91.             'company' => $company,
  92.         ]);
  93.     }
  94.     /**
  95.      * @param UserPermissionRepository $permissionRepository
  96.      *
  97.      * @return \Symfony\Component\HttpFoundation\Response
  98.      */
  99.     #[Route(path'/'name'home')]
  100.     public function index(UserPermissionRepository $permissionRepository): Response
  101.     {
  102.         $dashboardPermissions $permissionRepository->findBy(['permission_user' => $this->security->getUser()]);
  103.         $rootNode $this->determineRootNode($dashboardPermissions);
  104.         if ($rootNode) {
  105.             switch ($rootNode->getEntityType()) {
  106.                 case 'company':
  107.                     return $this->getCompanyLevelData($this->dashboardStats);
  108.                     break;
  109.                 case 'location':
  110.                     return $this->locationRootData($rootNode->getEntityId()->toString());
  111.                     break;
  112.                 case 'employee':
  113.                     return $this->employeeRootData($rootNode->getEntityId()->toString());
  114.                     break;
  115.             }
  116.         }
  117.         return $this->redirect('/admin');
  118.     }
  119.     private function determineRootNode(array $permissions)
  120.     {
  121.         $nodeOrder = [
  122.             'company',
  123.             'location',
  124.             'department',
  125.             'employee',
  126.         ];
  127.         foreach ($nodeOrder as $nodeType) {
  128.             foreach ($permissions as $permission) {
  129.                 if ($permission->getEntityType() == $nodeType) {
  130.                     return $permission;
  131.                 }
  132.             }
  133.         }
  134.     }
  135.     /**
  136.      * @param Request               $request
  137.      * @param DashboardStatsService $dashboardStats
  138.      * @param int                   $chartIndex
  139.      *
  140.      * @return Response
  141.      */
  142.     #[Route(path'/dashboard/period-chart/company/{chartIndex}')]
  143.     public function getCompanyPeriodChart(Request $requestDashboardStatsService $dashboardStatsint $chartIndex): Response
  144.     {
  145.         $totalScores $dashboardStats->getTotalStats();
  146.         if (count($totalScores) > $this->periodService->getPeriodsToShow()) {
  147.             $sliceOffset $this->periodService->getPeriodsToShow() * -1;
  148.             $totalScores array_slice($totalScores$sliceOffset);
  149.         }
  150.         $periodKeys array_keys($totalScores);
  151.         $currentPeriodKey $periodKeys[$chartIndex];
  152.         $currentValues $totalScores[$currentPeriodKey];
  153.         $this->fillSkillGroupSettings();
  154.         $scores = [];
  155.         $scoreTotal $currentValues['total_avg'];
  156.         foreach ($this->quads as $i => $name) {
  157.             $scores[$i] = [
  158.                 'name' => $name,
  159.                 'score' => $currentValues['quad'.$i.'_avg'],
  160.             ];
  161.         }
  162.         $scores[5] = ['name' => 'Growth Opportunity''score' => 100 $scoreTotal];
  163.         return $this->render('dashboard-stimulus/partials/_entity_score_period_donut.html.twig', [
  164.                 'reviewPeriod' => $currentPeriodKey,
  165.                 'scores' => $scores,
  166.                 'scoreTotal' => $scoreTotal,
  167.                 'colorSets' => $this->colorSets,
  168.                 'reviewDirection' => 'up'// TODO: make this correct
  169.                 'skillGroupNames' => $this->quads,
  170.                 'currentScore' => $scoreTotal,
  171.             ]
  172.         );
  173.     }
  174.     /**
  175.      * @param Request               $request
  176.      * @param DashboardStatsService $dashboardStats
  177.      * @param int                   $chartIndex
  178.      *
  179.      * @return Response
  180.      */
  181.     #[Route(path'/dashboard/period-chart/location/{locationId}/{chartIndex}')]
  182.     public function getLocationPeriodChart(Request $requestDashboardStatsService $dashboardStatsstring $locationIdint $chartIndex): Response
  183.     {
  184.         $totalScores $dashboardStats->getLocationTotalStats($locationId);
  185.         $totalScores current($totalScores);
  186.         if (count($totalScores) > $this->periodService->getPeriodsToShow()) {
  187.             $sliceOffset $this->periodService->getPeriodsToShow() * -1;
  188.             $totalScores array_slice($totalScores$sliceOffset);
  189.         }
  190.         $periodKeys array_keys($totalScores);
  191.         $currentPeriodKey $periodKeys[$chartIndex];
  192.         $currentValues $totalScores[$currentPeriodKey];
  193.         $this->fillSkillGroupSettings();
  194.         $scores = [];
  195.         $scoreTotal $currentValues['total_avg'];
  196.         foreach ($this->quads as $i => $name) {
  197.             $scores[$i] = [
  198.                 'name' => $name,
  199.                 'score' => $currentValues['quad'.$i.'_avg'],
  200.             ];
  201.         }
  202.         $scores[5] = ['name' => 'Growth Opportunity''score' => 100 $scoreTotal];
  203.         return $this->render('dashboard-stimulus/partials/_entity_score_period_donut.html.twig', [
  204.                 'reviewPeriod' => $currentPeriodKey,
  205.                 'scores' => $scores,
  206.                 'scoreTotal' => $scoreTotal,
  207.                 'colorSets' => $this->colorSets,
  208.                 'reviewDirection' => 'up'// TODO: make this correct
  209.                 'skillGroupNames' => $this->quads,
  210.                 'currentScore' => $scoreTotal,
  211.             ]
  212.         );
  213.     }
  214.     private function getCompanyLevelData(DashboardStatsService $dashboardStats)
  215.     {
  216.         $periods $this->getPeriods();
  217.         $this->fillSkillGroupSettings();
  218.         $currentPeriod end($periods);
  219.         $previousPeriod prev($periods);
  220.         reset($periods);
  221.         $company $this->getCompanyInfo();
  222.         $companyStats $dashboardStats->getTotalStats();
  223.         $locationStats $dashboardStats->getLocationTotalStats();
  224.         $currentPeriodStats end($companyStats);
  225.         $previousPeriodStats prev($companyStats);
  226.         $currentPieData $this->pieDataService->calculateSkillGroupPieDataFromStatsArray($currentPeriodStats$this->quads);
  227.         $previousPieData $this->pieDataService->calculateSkillGroupPieDataFromStatsArray($previousPeriodStats$this->quads);
  228.         $totalScores = [];
  229.         foreach ($companyStats as $period => $stats) {
  230.             $period substr($period2);
  231.             $totalScores[$period] = $stats['total_avg'];
  232.         }
  233.         if (count($totalScores) > $this->periodService->getPeriodsToShow()) {
  234.             $sliceOffset $this->periodService->getPeriodsToShow() * -1;
  235.             $totalScores array_slice($totalScores$sliceOffset);
  236.         }
  237.         $locations $this->getLocations();
  238.         $locationMap = [];
  239.         foreach ($locations as $location) {
  240.             $locationMap[$location->getId()->toString()] = $location;
  241.         }
  242.         $locationTotals = [];
  243.         $locationTrends = [];
  244.         foreach ($locationStats as $locationId => $periodStats) {
  245.             $locationTotals[$locationId] = [
  246.                 'prevTotals' => 0,
  247.                 'totals' => 0,
  248.                 'skillGroups' => [],
  249.                 'info' => $locationMap[$locationId],
  250.                 'prevDiff' => 0,
  251.             ];
  252.             if (count($periodStats)) {
  253.                 $lastQuarter end($periodStats);
  254.                 $locationTotals[$locationId]['skillGroups'] = [
  255.                     => $lastQuarter['quad1_avg'],
  256.                     => $lastQuarter['quad2_avg'],
  257.                     => $lastQuarter['quad3_avg'],
  258.                     => $lastQuarter['quad4_avg'],
  259.                 ];
  260.                 $locationTotals[$locationId]['totals'] = $lastQuarter['total_avg'];
  261.             }
  262.             if (count($periodStats) > 1) {
  263.                 $prevQuarter prev($periodStats);
  264.                 $locationTotals[$locationId]['prevTotals'] = $prevQuarter['total_avg'];
  265.                 $locationTotals[$locationId]['prevDiff'] = $locationTotals[$locationId]['totals'] - $locationTotals[$locationId]['prevTotals'];
  266.             }
  267.             $locationTrends[$locationId] = [];
  268.             foreach ($periodStats as $period => $stats) {
  269.                 $locationTrends[$locationId][$period] = $stats['total_avg'];
  270.             }
  271.         }
  272.         return $this->render('dashboard-stimulus/index.html.twig', [
  273.             'controller_name' => 'DashboardController',
  274.             'totalScores' => $totalScores,
  275.             'periods' => $periods,
  276.             'company' => $company,
  277.             'entity' => $company,
  278.             'locations' => $locations,
  279.             'pieData' => $currentPieData,
  280.             'previousPieData' => $previousPieData,
  281.             'locationScores' => $locationTotals,
  282.             'locationTrends' => $locationTrends,
  283.             'skillGroupNames' => $this->quads,
  284.             'entityId' => $company->getId()->toString(),
  285.             'childScores' => $locationTotals,
  286.             'childTrends' => $locationTrends,
  287.             'entityType' => 'company',
  288.             'childType' => 'location',
  289.             'isRoot' => true,
  290.         ]);
  291.     }
  292.     private function skillGroupPieData(array $reviews null$single false$period null)
  293.     {
  294.         if (is_null($reviews)) {
  295.             $reviews $this->getReviews();
  296.         }
  297.         if (is_null($period)) {
  298.             $periods $this->getPeriods();
  299.             $period array_pop($periods);
  300.         }
  301.         $pieData $this->pieDataService->calculateSkillGroupPieDataFromReviews($reviews$single$period$this->quads);
  302.         return $pieData;
  303.     }
  304.     /**
  305.      * @param Request $request
  306.      * @param string  $reviewId
  307.      *
  308.      * @return \Symfony\Component\HttpFoundation\Response
  309.      *
  310.      * @throws \Exception
  311.      */
  312.     #[Route(path'/dashboard/review-data/{reviewId}')]
  313.     public function getReviewData(Request $requeststring $reviewId): Response
  314.     {
  315.         $company $this->getCompanyInfo();
  316.         $this->fillSkillGroupSettings();
  317.         /** @var EmployeeReview $review */
  318.         $review $this->getDoctrine()->getRepository(EmployeeReview::class)->findOneBy(['id' => $reviewId]);
  319.         $positionVersion $review->getPositionVersion();
  320.         $settings json_decode($positionVersion->getSettings(), true);
  321.         $employeeId $review->getEmployee()->getId()->toString();
  322.         $currentScore $request->query->get('currentScore');
  323.         $previousScore $request->query->get('previousScore');
  324.         $previousReviewId $request->query->get('previousReviewId');
  325.         $reviewDirection '';
  326.         if ($previousScore != 'null' && $currentScore $previousScore) {
  327.             $reviewDirection 'up';
  328.         } elseif ($previousScore $currentScore) {
  329.             $reviewDirection 'down';
  330.         }
  331.         $scores = [];
  332.         $scoreTotal 0;
  333.         $goalTotal 0;
  334.         foreach ($settings['positionQuads'] as $skillGroup) {
  335.             $num $skillGroup['quadSetting']['positionNumber'];
  336.             $scores[$num] = [
  337.                 'name' => $skillGroup['quadSetting']['name'],
  338.                 'score' => $review->getQuadScore($num),
  339.             ];
  340.             $scoreTotal += $review->getQuadScore($num);
  341.         }
  342.         $scores[5] = [
  343.             'name' => 'Growth Opportunity',
  344.             'score' => 100 $scoreTotal,
  345.         ];
  346.         return $this->render('dashboard-stimulus/partials/_review-preview-panel.html.twig', [
  347.             'positionName' => $review->getPosition()->getName(),
  348.             'reviewQuarter' => $review->getReviewQuarter(),
  349.             'reviewDate' => $review->getReviewDate(),
  350.             'scores' => $scores,
  351.             'scoreTotal' => $scoreTotal,
  352.             'reviewId' => $reviewId,
  353.             'colorSets' => $this->colorSets,
  354.             'company' => $company,
  355.             'reviewDirection' => $reviewDirection,
  356.             'skillGroupNames' => $this->quads,
  357.             'employeeId' => $employeeId,
  358.             'employeeName' => $review->getEmployee()->getDisplayName(),
  359.             'currentScore' => $currentScore,
  360.             'previousScore' => $previousScore,
  361.             'previousReviewId' => $previousReviewId,
  362.         ]);
  363.     }
  364.     private function locationRootData($locationId)
  365.     {
  366.         $locationData $this->getLocationPanelData($locationId$this->dashboardStats);
  367.         return $this->render('dashboard/index-location.html.twig'$locationData);
  368.     }
  369.     /**
  370.      * @param Request $request
  371.      * @param string $locationId
  372.      * @param DashboardStatsService $dashboardStatsService
  373.      *
  374.      * @return \Symfony\Component\HttpFoundation\Response
  375.      */
  376.     #[Route(path'/dashboard/location-aggregate/{locationId}')]
  377.     public function getLocationAggregateData(Request $requeststring $locationIdDashboardStatsService $dashboardStatsService): Response
  378.     {
  379.         $locationData $this->getLocationPanelData($locationId$dashboardStatsService);
  380.         return $this->render('dashboard-stimulus/partials/_panel.html.twig'$locationData);
  381.     }
  382.     /**
  383.      * @return array
  384.      */
  385.     private function getLocationPanelData(string $locationIdDashboardStatsService $dashboardStatsService)
  386.     {
  387.         $this->fillSkillGroupSettings();
  388.         $company $this->getCompanyInfo();
  389.         $reviews = [];
  390.         /** @var Location $location */
  391.         $location $this->getDoctrine()->getRepository(Location::class)->findBy(['id' => $locationId])[0];
  392.         $employees $this->getDoctrine()->getRepository(Employee::class)->findBy(['location' => $locationId]);
  393.         uasort($employees, function (Employee $aEmployee $b) {
  394.             return $a->getDisplayName() <=> $b->getDisplayName();
  395.         });
  396.         $dashboardStatsTotalScores $dashboardStatsService->getLocationTotalStats($locationId);
  397.         $dashboardStatsEmployeeScores $dashboardStatsService->getLocationEmployeeTotalStats($locationId);
  398.         $totalScores = [];
  399.         $scores = [];
  400.         if (isset($dashboardStatsTotalScores[$locationId])) {
  401.             $scores $this->pruneStatPeriods($dashboardStatsTotalScores[$locationId]);
  402.             foreach ($scores as $key => $data) {
  403.                 $key substr($key2);
  404.                 $totalScores[$key] = $data['total_avg'];
  405.             }
  406.         }
  407.         $periods array_keys($totalScores);
  408.         $currentPeriodStats end($scores);
  409.         $previousPeriodStats prev($scores);
  410.         $employeeScoreData $this->compileEmployeeStatLines($dashboardStatsEmployeeScores$employees);
  411.         return [
  412.             'totalScores' => $totalScores,
  413.             'pieData' => $this->pieDataService->calculateSkillGroupPieDataFromStatsArray($currentPeriodStats$this->quads),
  414.             'previousPieData' => $this->pieDataService->calculateSkillGroupPieDataFromStatsArray($previousPeriodStats$this->quads),
  415.             'location' => $location,
  416.             'periods' => $periods,
  417.             'employeeScores' => $employeeScoreData['employeeTotals'],
  418.             'employeeTrends' => $employeeScoreData['employeeTrends'],
  419.             'company' => $company,
  420.             'employees' => $employees,
  421.             'skillGroupNames' => $this->quads,
  422.             'entity' => $location,
  423.             'childScores' => $employeeScoreData['employeeTotals'],
  424.             'childTrends' => $employeeScoreData['employeeTrends'],
  425.             'entityId' => $location->getId()->toString(),
  426.             'childType' => 'employee',
  427.             'entityType' => 'location',
  428.         ];
  429.     }
  430.     private function compileEmployeeStatLines(array $scores, array $employees)
  431.     {
  432.         $periods $this->getPeriods();
  433.         reset($periods);
  434.         uasort($employees, function (Employee $aEmployee $b) {
  435.             return $a->getDisplayName() <=> $b->getDisplayName();
  436.         });
  437.         $employeeTotals = [];
  438.         $employeeTrends = [];
  439.         foreach ($employees as $employee) {
  440.             $employeeTotals[$employee->getId()->toString()] = [
  441.                 'totals' => null,
  442.                 'prevTotal' => null,
  443.                 'prevDiff' => null,
  444.                 'skillGroups' => [],
  445.                 'info' => $employee,
  446.             ];
  447.         }
  448.         foreach ($employeeTotals as $employeeId => $blank) {
  449.             $prunedScores $this->pruneStatPeriods($scores[$employeeId]);
  450.             $latestReview end($prunedScores);
  451.             $total $latestReview['total_avg'];
  452.             if (count($prunedScores) > 1) {
  453.                 $previousReview prev($prunedScores);
  454.                 $prevTotal $previousReview['total_avg'];
  455.                 $prevDiff $total $prevTotal;
  456.             } else {
  457.                 $previousReview null;
  458.                 $prevTotal null;
  459.                 $prevDiff null;
  460.             }
  461.             $totals = [
  462.                 'totals' => $total,
  463.                 'prevTotal' => $prevTotal,
  464.                 'prevDiff' => round($prevDiff1),
  465.                 'skillGroups' => [
  466.                     $this->quads[1] => $latestReview['quad1_avg'],
  467.                     $this->quads[2] => $latestReview['quad2_avg'],
  468.                     $this->quads[3] => $latestReview['quad3_avg'],
  469.                     $this->quads[4] => $latestReview['quad4_avg'],
  470.                 ],
  471.             ];
  472.             $employeeTotals[$employeeId] = array_merge($employeeTotals[$employeeId], $totals);
  473.             foreach ($prunedScores as $score) {
  474.                 $employeeTrends[$employeeId][$score['review_period']] = $score['total_avg'];
  475.             }
  476.         }
  477.         return [
  478.             'employeeTotals' => $employeeTotals,
  479.             'employeeTrends' => $employeeTrends,
  480.         ];
  481.     }
  482.     protected function employeeRootData(string $employeeId)
  483.     {
  484.         $employeeData $this->getEmployeePanelData($employeeId);
  485.         $employeeData['companyInfo'] = $this->getCompanyInfo();
  486.         $employeeData['skillGroupNames'] = $this->quads;
  487.         return $this->render('dashboard-stimulus/index.html.twig'$employeeData);
  488.     }
  489.     /**
  490.      * @param Request $request
  491.      * @param string  $employeeId
  492.      *
  493.      * @return \Symfony\Component\HttpFoundation\Response
  494.      *
  495.      * @throws \Exception
  496.      */
  497.     #[Route(path'/dashboard/employee-aggregate/{employeeId}')]
  498.     public function getEmployeeAggregateData(Request $requeststring $employeeId): Response
  499.     {
  500.         $employeeData $this->getEmployeePanelData($employeeId);
  501.         return $this->render('dashboard-stimulus/partials/_panel.html.twig'$employeeData);
  502.     }
  503.     private function getEmployeePanelData(string $employeeId)
  504.     {
  505.         $this->fillSkillGroupSettings();
  506.         $reviews = [];
  507.         /** @var Employee $employee */
  508.         $employee $this->getDoctrine()->getRepository(Employee::class)->findBy(['id' => $employeeId])[0];
  509.         $employeePositions $this->getDoctrine()->getRepository(EmployeePosition::class)->findBy(['employee' => $employee]);
  510.         /** @var EmployeeReview[] $reviewList */
  511.         $reviewList = [];
  512.         $reviews $this->getDoctrine()->getRepository(EmployeeReview::class)->findBy(['employee' => $employee]);
  513.         foreach ($reviews as $review) {
  514.             $reviewEmployeeId $review->getEmployee()->getId()->toString();
  515.             if ($employeeId == $reviewEmployeeId) {
  516.                 $reviewPeriodKey $this->getReviewPeriodKey($review);
  517.                 $reviewPeriodKey substr($reviewPeriodKey2);
  518.                 $reviews[$reviewPeriodKey] = $review;
  519.                 $reviewList[$reviewPeriodKey] = $review->getId();
  520.             }
  521.         }
  522.         ksort($reviews);
  523.         $lastReview end($reviews);
  524.         $prevReview null;
  525.         if (count($reviews) > 1) {
  526.             $prevReview prev($reviews);
  527.         }
  528.         $skillScores = [];
  529.         $lastReviewData = [];
  530.         if ($lastReview) {
  531.             foreach ($lastReview->getEmployeeReviewsSkillScores() as $score) {
  532.                 if (!isset($skillScores[$score->getPositionQuadSkillId()])) {
  533.                     $skillScores[$score->getPositionQuadSkillId()] = [
  534.                         'score' => 0,
  535.                     ];
  536.                 }
  537.                 $skillScores[$score->getPositionQuadSkillId()]['score'] += $score->getScore();
  538.             }
  539.             $lastReviewSettings json_decode($lastReview->getPositionVersion()->getSettings(), true);
  540.             foreach ($lastReviewSettings['positionQuads'] as $positionSkillGroup) {
  541.                 $skillGroup = [
  542.                     'id' => $positionSkillGroup['id'],
  543.                     'name' => $positionSkillGroup['quadSetting']['name'],
  544.                     'positionNumber' => $positionSkillGroup['quadSetting']['positionNumber'],
  545.                     'skills' => [],
  546.                 ];
  547.                 foreach ($positionSkillGroup['positionQuadSkills'] as $skill) {
  548.                     $skillGroup['skills'][$skill['id']] = [
  549.                         'id' => $skill['id'],
  550.                         'title' => $skill['nameOverride'],
  551.                         'description' => $skill['definitionOverride'],
  552.                         'positionNumber' => $skill['positionNumber'],
  553.                         'score' => $skillScores[$skill['id']]['score'],
  554.                     ];
  555.                 }
  556.                 $lastReviewData['skillGroups'][$skillGroup['id']] = $skillGroup;
  557.                 $lastReviewData['id'] = $lastReview->getId();
  558.             }
  559.         }
  560.         $totalScores array_fill_keys($this->getPeriods(), '');
  561.         $totalScores array_merge($totalScores$this->getTotalScores($reviews));
  562.         ksort($totalScores);
  563.         foreach ($totalScores as $period => $score) {
  564.             if ($score == '') {
  565.                 unset($totalScores[$period]);
  566.             }
  567.         }
  568.         $periods array_keys($totalScores);
  569.         $currentPeriod end($periods);
  570.         $previousPeriod prev($periods);
  571.         reset($periods);
  572.         $newTotalScores = [];
  573.         foreach ($totalScores as $period => $score) {
  574.             $period substr($period2);
  575.             $newTotalScores[$period] = $score;
  576.         }
  577.         $totalScores $newTotalScores;
  578.         $employeeStats $this->dashboardStats->getEmployeeTotalStats($employeeId);
  579.         return [
  580.             'totalScores' => $totalScores,
  581.             'pieData' => $this->skillGroupPieData($reviewstrue$currentPeriod),
  582.             'previousPieData' => $this->skillGroupPieData($reviewstrue$previousPeriod),
  583.             'employee' => $employee,
  584.             'periods' => $periods,
  585.             'lastReview' => $lastReviewData,
  586.             'reviewList' => $reviewList,
  587.             'companyInfo' => $this->getCompanyInfo(),
  588.             'skillGroupNames' => $this->quads,
  589.             'position' => $employeePositions[0]->getPosition(),
  590.             'entity' => $employee,
  591.             'entityId' => $employee->getId()->toString(),
  592.             'entityType' => 'employee',
  593.             'location' => $employee->getLocation(),
  594.             'employeeStats' => $employeeStats,
  595.             'locations' => $this->getLocations(),
  596.         ];
  597.     }
  598.     protected function getTotalScores(array $allReviews null)
  599.     {
  600.         if (is_null($allReviews)) {
  601.             $allReviews $this->getReviews();
  602.         }
  603.         $totals = [];
  604.         foreach ($allReviews as $review) {
  605.             $periodKey $this->getReviewPeriodKey($review);
  606.             $reviewTotal 0;
  607.             foreach ($review->getQuadTotals()['positionQuads'] as $score) {
  608.                 $reviewTotal += $score['scoreTotal'];
  609.             }
  610.             if (!isset($totals[$periodKey])) {
  611.                 $totals[$periodKey] = [];
  612.             }
  613.             $totals[$periodKey][] = $reviewTotal;
  614.         }
  615.         $periodTotals = [];
  616.         foreach ($totals as $qKey => $scores) {
  617.             $periodTotals[$qKey] = (array_sum($scores) / count($scores));
  618.         }
  619.         ksort($periodTotals);
  620.         if (count($periodTotals) > $this->periodService->getPeriodsToShow()) {
  621.             $sliceOffset $this->periodService->getPeriodsToShow() * -1;
  622.             $periodTotals array_slice($periodTotals$sliceOffset);
  623.         }
  624.         return $periodTotals;
  625.     }
  626.     protected function getSkillGroupTotalScores(array $allReviews nullstring $skillGroupId)
  627.     {
  628.         if (is_null($allReviews)) {
  629.             $allReviews $this->getReviews();
  630.         }
  631.         $totals = [];
  632.         foreach ($allReviews as $review) {
  633.             $reviewQuarter ceil($review->getReviewDate()->format('n') / 3);
  634.             $qKey $review->getReviewDate()->format('y').'Q'.$reviewQuarter;
  635.             $reviewTotal 0;
  636.             foreach ($review->getQuadTotals()['positionQuads'] as $score) {
  637.                 if ($score['id'] !== $skillGroupId) {
  638.                     continue;
  639.                 }
  640.                 $reviewTotal += $score['scoreTotal'];
  641.             }
  642.             if (!isset($totals[$qKey])) {
  643.                 $totals[$qKey] = [];
  644.             }
  645.             $totals[$qKey][] = $reviewTotal;
  646.         }
  647.         $periodTotals = [];
  648.         foreach ($totals as $qKey => $scores) {
  649.             $periodTotals[$qKey] = (array_sum($scores) / count($scores));
  650.         }
  651.         ksort($periodTotals);
  652.         while (count($periodTotals) > $this->periodService->getPeriodsToShow()) {
  653.             array_shift($periodTotals);
  654.         }
  655.         return $periodTotals;
  656.     }
  657.     /**
  658.      * @return EmployeeReview[]
  659.      */
  660.     protected function getReviews()
  661.     {
  662.         /* @var EmployeeReview[] $allReviews */
  663.         if (!$this->allReviews) {
  664.             $allReviews $this->getDoctrine()->getRepository(EmployeeReview::class)->findAll();
  665.             $this->allReviews $allReviews;
  666.         }
  667.         return $this->allReviews;
  668.     }
  669.     protected function getPeriods()
  670.     {
  671.         return $this->periodService->getPeriods();
  672.     }
  673.     protected function getReviewPeriodKey(EmployeeReview $review): string
  674.     {
  675.         return $this->periodService->getPeriodKey($review->getReviewDate());
  676.     }
  677.     protected function getLocations()
  678.     {
  679.         if (!$this->locations) {
  680.             $locations $this->getDoctrine()->getRepository(Location::class)->findAll();
  681.             $this->locations $locations;
  682.         }
  683.         return $this->locations;
  684.     }
  685.     protected function getCompanyInfo()
  686.     {
  687.         $companyInfo $this->getDoctrine()->getRepository(Company::class)->findAll();
  688.         if (isset($companyInfo[0])) {
  689.             $company $companyInfo[0];
  690.         } else {
  691.             $company null;
  692.         }
  693.         return $company;
  694.     }
  695.     protected function fillSkillGroupSettings()
  696.     {
  697.         $skillGroupSettings $this->getDoctrine()->getRepository(QuadSettings::class)->findAll();
  698.         if (count($skillGroupSettings)) {
  699.             $this->quads = [];
  700.             /** @var QuadSettings $skillGroupSetting */
  701.             foreach ($skillGroupSettings as $skillGroupSetting) {
  702.                 $this->quads[$skillGroupSetting->getPositionNumber()] = $skillGroupSetting->getName();
  703.             }
  704.         }
  705.     }
  706.     protected function pruneStatPeriods($data)
  707.     {
  708.         if (count($data) > $this->periodService->getPeriodsToShow()) {
  709.             $sliceOffset $this->periodService->getPeriodsToShow() * -1;
  710.             $data array_slice($data$sliceOffset);
  711.         }
  712.         return $data;
  713.     }
  714.     /**
  715.      * @param Request $request
  716.      * @param string  $employeeId
  717.      *
  718.      * @return \Symfony\Component\HttpFoundation\Response
  719.      *
  720.      * @throws \Exception
  721.      */
  722.     #[Route(path'/profile/employee/{employeeId}'name'employee_profile')]
  723.     public function getEmployeeProfile(Request $requeststring $employeeId): Response
  724.     {
  725.         $employeeData $this->getEmployeePanelData($employeeId);
  726.         $employeeData['company'] = $this->getCompanyInfo();
  727.         $employeeData['locations'] = $this->getLocations();
  728.         $employeeData['skillGroupNames'] = $this->quads;
  729.         $employeeData['isRoot'] = 1;
  730.         $employee $this->getDoctrine()->getRepository(Employee::class)->findOneBy(['id' => $employeeId]);
  731.         $employeeData['employee'] = $employee;
  732.         $employeeData['employeeMenu'] = 1;
  733.         $employeeData['employeeId'] = $employeeId;
  734.         return $this->render('dashboard-stimulus/index.html.twig'$employeeData);
  735.     }
  736. }