src/Controller/Api/ProfilesController.php line 80

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api;
  3. use App\Entity\AgeCategories;
  4. use App\Entity\CardiometabolicProfiles;
  5. use App\Entity\CardiovascularScore;
  6. use App\Entity\Countries;
  7. use App\Entity\CvdAdvices;
  8. use App\Entity\CvdRisks;
  9. use App\Entity\NonHdlCholesterol;
  10. use App\Entity\ScoreRisk;
  11. use App\Entity\SystolicBloodPresure;
  12. use App\Entity\Users;
  13. use App\Entity\UnitMeasureHba1cType;
  14. use App\Entity\UnitMeasureConcentrationType;
  15. use App\Helper\ConvertUnitMeasures;
  16. use App\Helper\HealthHelper;
  17. use App\Helper\LangHelper;
  18. use App\Services\Gamification\ProfileGamification;
  19. use App\Services\Health\CvdRiskPredictionBMI;
  20. use App\Services\Health\CvdRiskPredictionLipids;
  21. use App\Services\Health\GenCardioLipids;
  22. use App\Services\Health\MenParameters;
  23. use App\Services\Health\WomenParameters;
  24. use App\Services\Notifications\FcmNotifications;
  25. use App\Traits\ProfilesTrait;
  26. use Doctrine\ORM\EntityManagerInterface;
  27. use Dompdf\Dompdf;
  28. use Dompdf\Options;
  29. use Exception;
  30. use Psr\Log\LoggerInterface;
  31. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  32. use Symfony\Component\HttpFoundation\Request;
  33. use Symfony\Component\HttpFoundation\Response;
  34. use Symfony\Component\Routing\Annotation\Route;
  35. use Symfony\Contracts\Translation\TranslatorInterface;
  36. class ProfilesController extends AbstractController
  37. {
  38.     use ProfilesTrait;
  39.     use \App\Controller\Response;
  40.     protected TranslatorInterface $translator;
  41.     protected EntityManagerInterface $em;
  42.     public function __construct(TranslatorInterface $translatorEntityManagerInterface $em)
  43.     {
  44.         $this->translator $translator;
  45.         $this->em $em;
  46.     }
  47.     #[Route('/api/profiles/history'
  48.         name'app_api_profiles_history'methods: ["GET"])]
  49.     public function history(EntityManagerInterface $em): Response
  50.     {
  51.         $user $this->getUser();
  52.         if (!$user or ! $user instanceof Users) {
  53.             $type is_null($user) ? 'null' get_class($user);
  54.             return $this->errorJsonResponse(['message' => "User not found or invalid ($type)"]);
  55.         }
  56.         $profiles $em->getRepository(CardiometabolicProfiles::class)->findBy(['userId' => $user->getId(), 'masterProfile' => true], ['id' => 'DESC']);
  57.         return $this->json([
  58.             'status' => 'ok',
  59.             'data' => $profiles,
  60.         ], 200, [], ['groups' => ["profile""profiles:extended"]]);
  61.     }
  62.     protected function getHealthyScore(CardiometabolicProfiles $profile$lang)
  63.     {
  64.         $ageCategory $this->em->getRepository(AgeCategories::class)->getCategoryByAge($profile->getAge());
  65.         $country $this->em->getRepository(Countries::class)->find($profile->getCountryId() ?? 175);
  66.         $cvdRisk $this->em->getRepository(CvdRisks::class)->find($country->getRiskId() ?? 1);
  67.         $systolicBloodPresure $this->em->getRepository(SystolicBloodPresure::class)
  68.             ->getByValue($profile->getSystolicBloodPressure() ?? 0);
  69.         $nonHdlCholesterol $this->em->getRepository(NonHdlCholesterol::class)
  70.             ->getByValue($profile->getNonHdlCholesterol() ?? 0);
  71.         $criteria = [
  72.             'gender' => $profile->getGender(),
  73.             'smoking' => 0,
  74.             'systolicBloodPresureId' => $systolicBloodPresure $systolicBloodPresure->getId() : 0,
  75.             'ageCategoryId' => $ageCategory $ageCategory->getId() : 0,
  76.             'nonHdlCholesterolId' => $nonHdlCholesterol $nonHdlCholesterol->getId() : 0,
  77.             'cvdRiskId' => $cvdRisk $cvdRisk->getId() : null,
  78.             'removed' => 0,
  79.         ];
  80.         $cvdScore $this->em->getRepository(CardiovascularScore::class)->findOneBy($criteria);
  81.         if ($cvdScore) {
  82.             $scoreRisk $this->em->getRepository(ScoreRisk::class)->find($cvdScore->getScoreRiskId());
  83.         }
  84.         $scoreRisk HealthHelper::getScoreRisk($profile$scoreRisk ?? null$this->em);
  85.         $riskFlag false;
  86.         if (!empty($scoreRisk)) {
  87.             if (in_array($scoreRisk->getId(), [2,3]) &&  // (high and very high)  TODO: score risk should be enum
  88.                 $profile->hasOneOrMoreSevereRiskConditions() && 
  89.                 $this->getUser() && $this->getUser()->hasValidSubscription()
  90.             ) $riskFlag true;
  91.             return [
  92.                 'risk_flag' => $riskFlag,
  93.                 'score_risk' => $this->parseScoreRisk($scoreRisk$lang),
  94.                 'cvd_score' => HealthHelper::parseScoreToArray(HealthHelper::getScore($profile$cvdScore ?? null$scoreRisk))
  95.             ];
  96.         }
  97.         return ['risk_flag' => $riskFlag];
  98.     }
  99.     #[Route('/api/cardiometabolic_profile/{userId}'
  100.         name'api_cardiometabolic_profile'methods: ["GET"])]
  101.     public function getCardiometabolicProfile($userIdRequest $requestEntityManagerInterface $em)
  102.     {
  103.         try {
  104.             $user $this->getUser(); // TOKEN
  105.             if (!$user or ! $user instanceof Users) {
  106.                 $type is_null($user) ? 'null' get_class($user);
  107.                 return $this->errorJsonResponse(['message' => "User not found or invalid ($type)"]);
  108.             }
  109.             /** @var CardiometabolicProfiles $profile */
  110.             $profile $em->getRepository(CardiometabolicProfiles::class)->getLastByUser($user->getId());
  111.             $parsedAdvices = [];
  112.             if (!$profile) {
  113.                 return $this->json([
  114.                     'status' => 'ok',
  115.                     'data' => null,
  116.                 ], 200, [], ['groups' => ["profile""cvd_score:read"]]);
  117.             }
  118.             if ($profile) {
  119.                 $country $em->getRepository(Countries::class)->find($profile->getCountryId());
  120.                 $advices $em->getRepository(CvdAdvices::class)->filter(
  121.                     LangHelper::getLangId($user->getLang()),
  122.                     $profile->getSmoker(),
  123.                     $profile->getImc() > 25,
  124.                     true,
  125.                     $profile->getDiabetesStatus(),
  126.                     $user->hasValidSubscription(),
  127.                     $profile->getCountryId()
  128.                 );
  129.                 // if no country advices, get all countries advices
  130.                 if (count($advices) === 0) {
  131.                     $advices $em->getRepository(CvdAdvices::class)->filter(
  132.                         LangHelper::getLangId($user->getLang()),
  133.                         $profile->getSmoker(),
  134.                         $profile->getImc() > 25,
  135.                         true,
  136.                         $profile->getDiabetesStatus(),
  137.                         $user->hasValidSubscription()
  138.                     );
  139.                 }
  140.                 foreach ($advices as $advice) {
  141.                     $parsedAdvices[] = [
  142.                         'id' => $advice->getId(),
  143.                         'advice' => $this->parseAdvice($advice$profile),
  144.                         'title' => $advice->getTitle(),
  145.                         'image' => $advice->getImage(),
  146.                         'path' => $request->getUriForPath('/assets/images/advices/'),
  147.                     ];
  148.                 }
  149.                 if ($this->useFraminghamAlgorithm($country->getRiskId(), $profile) && $profile->getHdlCholesterol() > && $profile->getTotalCholesterol() > && $profile->getSystolicBloodPressure() > 0) {
  150.                     $cvd_risk_prediction_using_lipids = (new GenCardioLipids(
  151.                         $profile->getGender() == ? new WomenParameters() : new MenParameters(),
  152.                         $profile->getGender() == 1,
  153.                         $profile->getAge(),
  154.                         $profile->getSystolicBloodPressure(),
  155.                         $profile->getHypertensionTreatment(),
  156.                         $profile->getSmoker(),
  157.                         $profile->getDiabetes(),
  158.                         $profile->getHdlCholesterol(),
  159.                         $profile->getTotalCholesterol()
  160.                     ))->generateCvdRiskPredictionUsingLipids();
  161.                     $cvd_risk_prediction_lipids = (new CvdRiskPredictionLipids())->calcGenCvdRiskPredictionLipids(
  162.                         $profile->getGender() == 0,
  163.                         $profile->getAge(),
  164.                         $profile->getSystolicBloodPressure(),
  165.                         $profile->getHypertensionTreatment(),
  166.                         $profile->getSmoker(),
  167.                         $profile->getDiabetes(),
  168.                         $profile->getHdlCholesterol(),
  169.                         $profile->getTotalCholesterol()
  170.                     );
  171.                 }
  172.                 if ($this->useFraminghamAlgorithm($country->getRiskId(), $profile) && $profile->getSystolicBloodPressure() > 0) {
  173.                     $cvd_risk_prediction_bmi = (new CvdRiskPredictionBMI())->calcGenCvdRiskPredictionBMI(
  174.                         $profile->getGender() == 0,
  175.                         $profile->getAge(),
  176.                         $profile->getSystolicBloodPressure(),
  177.                         $profile->getHypertensionTreatment(),
  178.                         $profile->getSmoker(),
  179.                         $profile->getDiabetes(),
  180.                         $profile->getImc()
  181.                     );
  182.                 }
  183.             }
  184.             // ar trebui sa vina null obiectul score_risk daca una din aceste informatii este 0. "totalCholesterol": 0, "hdlCholesterol": 0, "nonHdlCholesterol": 0
  185.             if ($profile->getCvdScoreId() > && $profile->getHdlCholesterol() > && $profile->getTotalCholesterol() > && $profile->getNonHdlCholesterol() > 0) {
  186.                 $cvdScore $em->getRepository(CardiovascularScore::class)->find($profile->getCvdScoreId());
  187.                 if ($cvdScore) {
  188.                     $scoreRisk $em->getRepository(ScoreRisk::class)->find($cvdScore->getScoreRiskId());
  189.                 }
  190.             }
  191.             $scoreRisk HealthHelper::getScoreRisk($profile$scoreRisk ?? null$em);
  192.             return $this->json([
  193.                 'status' => 'ok',
  194.                 'data' => $profile,
  195.                 'advices' => $parsedAdvices,
  196.                 'score_risk' => $this->parseScoreRisk($scoreRisk$user->getLang()),
  197.                 'cvd_score' => HealthHelper::parseScoreToArray(HealthHelper::getScore($profile$cvdScore ?? null$scoreRisk)),
  198.                 'params' => [
  199.                     'weight_loss' => ConvertUnitMeasures::convertKgByUnitMeasureType($user->getUnitMeasure(), HealthHelper::weightLoss($profile->getHeight(), $profile->getWeight())),
  200.                     'ldl_cholesterol_limit' => HealthHelper::getLdlLimit($profile),
  201.                 ],
  202.                 'cvd_risk_prediction_using_lipids' => $cvd_risk_prediction_using_lipids ?? null,
  203.                 'cvd_risk_prediction_bmi' => $cvd_risk_prediction_bmi ?? null,
  204.                 'cvd_risk_prediction_lipids' => $cvd_risk_prediction_lipids ?? null,
  205.                 'healthy_minutes' => $user->getHealthyMinutes(),
  206.                 'user_points' => $user->getUserPoints(),
  207.                 'healthiest_score' => $this->getHealthyScore($profile$user->getLang())
  208.             ], 200, [], ['groups' => ["profile""cvd_score:read"]]);
  209.         } catch (Exception $e) {
  210.             return $this->errorJsonResponse(['message' => $e->getMessage()]);
  211.         }
  212.     }
  213.     #[Route('/api/cardiometabolic_profile'
  214.         name'api_cardiometabolic_profile_save'methods: ["POST"])]
  215.     public function saveCardiometaboliProfile(
  216.         Request $request,
  217.         EntityManagerInterface $em,
  218.         LoggerInterface $appLogger,
  219.         FcmNotifications $fcmNotification
  220.     )
  221.     {
  222.         try {
  223.             $content $request->getContent();
  224.             # parse JSON to Array
  225.             $data json_decode($contenttrue);
  226.             $user $this->getUser();   // TOKEN
  227.             if (!$user or ! $user instanceof Users) {
  228.                 $type is_null($user) ? 'null' get_class($user);
  229.                 return $this->errorJsonResponse(['message' => "User not found or invalid ($type)"]);
  230.             }
  231.             $previousProfile $em->getRepository(CardiometabolicProfiles::class)->getLastMasterByUser($user->getId());
  232.             $country $em->getRepository(Countries::class)->find($data['country'] ?? 0);
  233.             $systolicBloodPresure $em->getRepository(SystolicBloodPresure::class)->getByValue($data['systolic_blood_pressure'] ?? 0);
  234.             $ageCategory $em->getRepository(AgeCategories::class)->getCategoryByAge($data['age'] ?? 0);
  235.             $nonHdlCholesterol $em->getRepository(NonHdlCholesterol::class)->getByValue($data['non_hdl_cholesterol'] ?? 0);
  236.             $cvdRisk $em->getRepository(CvdRisks::class)->find($country $country->getRiskId() : 0);
  237.             $cvdScore null;
  238.             if ($data['total_cholesterol'] > && $data['hdl_cholesterol'] > 0) {
  239.                 $criteria = [
  240.                     'gender' => $data['gender'] ?? 0,
  241.                     'smoking' => $data['smoker'] ? 0,
  242.                     'systolicBloodPresureId' => $systolicBloodPresure $systolicBloodPresure->getId() : 0,
  243.                     'ageCategoryId' => $ageCategory $ageCategory->getId() : 0,
  244.                     'nonHdlCholesterolId' => $nonHdlCholesterol $nonHdlCholesterol->getId() : 0,
  245.                     'cvdRiskId' => $cvdRisk $cvdRisk->getId() : 0,
  246.                     'removed' => 0,
  247.                 ];
  248.                 $cvdScore $em->getRepository(CardiovascularScore::class)->findOneBy($criteria);
  249.             }
  250.             $cardiometabolicProfile $em
  251.                 ->getRepository(CardiometabolicProfiles::class)
  252.                 ->createFromData($data$user->getId(),  $country->getId(), $cvdScore);
  253.             if ($user->hasValidSubscription()) {
  254.                 $gamification = new ProfileGamification(
  255.                     $cardiometabolicProfile
  256.                     $previousProfile
  257.                     $em
  258.                     $appLogger
  259.                     $this->getParameter('fcm_api_key')
  260.                 );
  261.                 $gamification->saveRewards();
  262.                 $em->flush();
  263.                 $gamification->sendNotifications($fcmNotification);
  264.             }
  265.             return $this->jsonResponse([
  266.                 'status' => 'ok',
  267.                 'gender' => $data['gender'] ?? 0,
  268.                 'smoking' => $data['smoker'] ?? 0,
  269.                 'systolicBloodPresureId' => $systolicBloodPresure $systolicBloodPresure->getId() : 0,
  270.                 'ageCategoryId' => $ageCategory $ageCategory->getId() : 0,
  271.                 'nonHdlCholesterolId' => $nonHdlCholesterol $nonHdlCholesterol->getId() : 0,
  272.                 'cvdRiskId' => $cvdRisk $cvdRisk->getId() : 0,
  273.                 'removed' => 0,
  274.             ]);
  275.         } catch (Exception $e) {
  276.             return $this->errorJsonResponse(['message' => $e->getMessage()]);
  277.         }
  278.     }
  279.     #[Route('/api/cardiometabolic_profile/pdf/{userId}'
  280.         name'api_cardiometabolic_profile_pdf'methods: ["GET"])]
  281.     public function getCardiometaboliProfilePdf($userIdEntityManagerInterface $em)
  282.     {
  283.         $user $this->getUser();   // TOKEN
  284.         if (!$user or ! $user instanceof Users) {
  285.             $type is_null($user) ? 'null' get_class($user);
  286.             return $this->errorJsonResponse(['message' => "User not found or invalid ($type)"]);
  287.         }
  288.         //$user = $em->getRepository(Users::class)->find($userId);
  289.         /** @var CardiometabolicProfiles $profile */
  290.         $profile $em->getRepository(CardiometabolicProfiles::class)->getLastByUser($user->getId());
  291.         $country $em->getRepository(Countries::class)->find($profile->getCountryId());
  292.         $cvdScore $em->getRepository(CardiovascularScore::class)->find($profile->getCvdScoreId() ?? 0);
  293.         $scoreRisk $em->getRepository(ScoreRisk::class)->find($cvdScore?->getScoreRiskId() ?? 0);
  294.         $scoreRisk HealthHelper::getScoreRisk($profile$scoreRisk$em);
  295.         // Configure Dompdf according to your needs
  296.         $pdfOptions = new Options();
  297.         $pdfOptions->set('defaultFont''Arial');
  298.         // Instantiate Dompdf with our options
  299.         $dompdf = new Dompdf($pdfOptions);
  300.         // Retrieve the HTML generated in our twig file
  301.         $html $this->renderView('pdf/profile.html.twig', [
  302.             'logo' => base64_encode(file_get_contents(__DIR__ '/../../../public/images/DAHNA_Powered-by-cardioscience_Logo.png')),
  303.             'lang' => $user->getLang(),
  304.             'has_valid_subscription' => $user->hasValidSubscription(),
  305.             'user' => [
  306.                 'name' => $user->getFullname(),
  307.                 'country' => $country->getCountryName(),
  308.                 'sex' => HealthHelper::getSex($profile->getGender()),
  309.                 'age' => $profile->getAge(),
  310.                 'weight' => $profile->getWeight(),
  311.                 'height' => $profile->getHeight(),
  312.             ],
  313.             'profile' => [
  314.                 'weight_loss' => HealthHelper::weightLoss($profile->getHeight(), $profile->getWeight()),
  315.                 'bmi' => $profile->getImc(),
  316.                 'score' => HealthHelper::getScore($profile$cvdScore$scoreRisk ?? null),
  317.                 'risk' => $scoreRisk $scoreRisk->getScoreRisk() : null,
  318.                 'risk_color' => $scoreRisk $scoreRisk->getColor() : '',
  319.                 'systolic_blood_pressure' => $profile->getSystolicBloodPressure(),
  320.                 'total_cholesterol' => $profile->getTotalCholesterol(true),
  321.                 'hdl_cholesterol' => $profile->getHdlCholesterol(true),
  322.                 'non_hdl_cholesterol' => $profile->getNonHdlCholesterol(true),
  323.                 'myocardial_infarction' => $profile->getMyocardialInfarction() ? 'Yes' 'No',
  324.                 'angina_pectoris' => $profile->getAnginaPectoris() ? 'Yes' 'No',
  325.                 'smoker' => $profile->getSmoker() ? 'Yes' 'No',
  326.                 'hypertension' => $profile->getHypertensionTreatment() ? 'Yes' 'No',
  327.                 'diabetes' => $profile->getDiabetes() ? 'Yes' 'No',
  328.                 'hypertension_treatment' => $profile->getHypertensionTreatment() ? 'Yes' 'No',
  329.                 'coronary_artery_bypass' => $profile->getCoronaryArteryBypass() ? 'Yes' 'No',
  330.                 'arthritis' => $profile->getArthritis() ? 'Yes' 'No',
  331.                 'stroke' => $profile->getStroke() ? 'Yes' 'No',
  332.                 'angioplasty' => $profile->getAngioplasty() ? 'Yes' 'No',
  333.                 'hba1c' => $profile->getHba1c(true),
  334.                 'fasting_blood_sugar' => $profile->getFastingBloodSugar(true),
  335.                 'creatinine' => $profile->getCreatinine(true),
  336.                 'egfr' => $profile->getEGFR(),
  337.                 'urea' => $profile->getUrea(true),
  338.                 'diabetes_diagnosis_year' => $profile->getDiabetesDiagnosisYear()
  339.             ],
  340.             'reference_values' => [
  341.                 'systolic_blood_pressure' => "100 - 200",
  342.                 'total_cholesterol' => 
  343.                     $profile->getUnitMeasureConcentration() == UnitMeasureConcentrationType::MG_PER_DL ?
  344.                         "< 200" "< 5.18",
  345.                 'hdl_cholesterol' => $profile->getUnitMeasureConcentration() == UnitMeasureConcentrationType::MG_PER_DL ?
  346.                     ($profile->getGender() == "> 50" "> 40") :
  347.                     ($profile->getGender() == "> 1.29" "> 1.04"),
  348.                 'non_hdl_cholesterol' => "-",
  349.                 'hba1c' => $profile->getUnitMeasureHba1c() == UnitMeasureHba1cType::PERCENT "< 5.7" "< 39",
  350.                 'fasting_blood_sugar' => $profile->getUnitMeasureConcentration() == UnitMeasureConcentrationType::MG_PER_DL ?
  351.                     "70 - 100" "3.9 - 5.6",
  352.                 'creatinine' => $profile->getUnitMeasureConcentration() == UnitMeasureConcentrationType::MG_PER_DL 
  353.                     ($profile->getGender() == "0.6 - 1.2" "0.5 - 1.1") :
  354.                     ($profile->getGender() == "> 53 - 106" "44 - 97"),
  355.                 'urea' => $profile->getUnitMeasureConcentration() == UnitMeasureConcentrationType::MG_PER_DL ?
  356.                     "15 - 45" "2.5 - 7.5",
  357.                 'egfr' => ">90"
  358.             ],
  359.             'unit_measures' => [
  360.                 'systolic_blood_pressure' => "mm Hg",
  361.                 'total_cholesterol' => $profile->getUnitMeasureConcentration()->value,
  362.                 'hdl_cholesterol' => $profile->getUnitMeasureConcentration()->value,
  363.                 'non_hdl_cholesterol' => $profile->getUnitMeasureConcentration()->value,
  364.                 'hba1c' => $profile->getUnitMeasureHba1c()->value,
  365.                 'fasting_blood_sugar' => $profile->getUnitMeasureConcentration()->value,
  366.                 'creatinine' => $profile->getUnitMeasureConcentration()->value,
  367.         'urea' => $profile->getUnitMeasureConcentration()->value,
  368.         'egfr' => 'mL/min/1.73 m²',
  369.             ]
  370.         ]);
  371.         // Load HTML to Dompdf
  372.         $dompdf->loadHtml($html);
  373.         // (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
  374.         $dompdf->setPaper('A4''portrait');
  375.         // Render the HTML as PDF
  376.         $dompdf->render();
  377.         // Output the generated PDF to Browser (force download)
  378.         $dompdf->stream("profil_cardiometabolic.pdf", [
  379.             "Attachment" => true,
  380.         ]);
  381.         exit();
  382.     }
  383. }