src/Controller/DefaultController.php line 39

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\DataLine;
  4. use App\Entity\DataLines;
  5. use App\Entity\DataSet;
  6. use App\Entity\Results;
  7. use App\Form\DataLinesType;
  8. use App\Form\DataSetType;
  9. use Exception;
  10. use Psr\Log\LoggerInterface;
  11. use RecursiveDirectoryIterator;
  12. use RecursiveIteratorIterator;
  13. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  14. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  15. use Symfony\Component\Stopwatch\Stopwatch;
  16. use Symfony\Component\HttpFoundation\File\UploadedFile;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. use Dompdf\Dompdf;
  20. use Dompdf\Options;
  21. use Symfony\Contracts\Translation\TranslatorInterface;
  22. use ZipArchive;
  23. class DefaultController extends AbstractController
  24. {
  25.     private $logger;
  26.     public function __construct(LoggerInterface $logger)
  27.     {
  28.         $this->logger $logger;
  29.     }
  30.     /**
  31.      * @Route("/", name="home")
  32.      * @Route("/presentation", name="presentation")
  33.      */
  34.     public function index()
  35.     {
  36.         return $this->render('index.html.twig');
  37.     }
  38.     /**
  39.      * @Route("/bmd", name="bmd")
  40.      */
  41.     public function analyze(Request $request)
  42.     {
  43.         $session $request->getSession();
  44.         $dataset = new DataSet();
  45.         $datalines = new DataLines();
  46.         $dataset->setId(random_int(0255));
  47.         $session->set('dataset'$dataset);
  48.         $form $this->createForm(DataSetType::class, $dataset);
  49.         $form->handleRequest($request);
  50.         if ($form->isSubmitted() && $form->isValid()) {
  51.             if (is_dir($user_folder $this->getParameter('upload_directory') . "/" $request->getSession()->getId())) {
  52.                 array_map('unlink'glob("$user_folder/*"));
  53.                 rmdir($user_folder);
  54.             }
  55.             mkdir($user_folder);
  56.             if ($dataset->getDataLoadMethod() === FALSE && !empty($dataset->getDataFile())) {
  57.                 /** @var UploadedFile $file */
  58.                 $file $form->get('datafile')->getData();
  59.                 $fileName "data.in";
  60.                 try {
  61.                     $file->move(
  62.                         $user_folder,
  63.                         $fileName
  64.                     );
  65.                 } catch (FileException $e) {
  66.                     // ... handle exception if something happens during file upload
  67.                     $this->addFlash('primary'$e->getMessage());
  68.                 }
  69.                 $dataset->setDataFile($fileName);
  70.                 try {
  71.                     if ($handle fopen($user_folder "/" $dataset->getDataFile(), "r")) {
  72.                         $delimiters = array(
  73.                             ';' => 0,
  74.                             ',' => 0,
  75.                             "\t" => 0,
  76.                             "|" => 0
  77.                         );
  78.                         $firstLine fgets($handle);
  79.                         foreach ($delimiters as $delimiter => &$count) {
  80.                             $count count(str_getcsv($firstLine$delimiter));
  81.                         }
  82.                         while (($data fgetcsv($handle"0"array_search(max($delimiters), $delimiters))) !== false) {
  83.                             $num count($data);
  84.                             //si la ligne ne contient pas toutes les informations (ex: ligne vide) on l'ignore
  85.                             if ($num 3) continue;
  86.                             $dataline = new DataLine();
  87.                             for ($c 0$c $num$c++) {
  88.                                 $dataline->setConcentration((int)$data[0]);
  89.                                 $dataline->setSubjects((int)$data[1]);
  90.                                 $dataline->setIncidence((int)$data[2]);
  91.                                 if ($dataset->getExposureType() === "several_durations") {
  92.                                     $dataline->setTime((int)$data[3]);
  93.                                 }
  94.                             }
  95.                             $datalines->addDataLine($dataline);
  96.                         }
  97.                         $dataset->setDataLines($datalines);
  98.                         fclose($handle);
  99.                     } else {
  100.                         throw new Exception ('The datafile can not be read.');
  101.                     }
  102.                 } catch (Exception $exception) {
  103.                     $this->addFlash('secondary'$exception->getMessage());
  104.                 }
  105.             } elseif ($dataset->getDataLoadMethod() === TRUE && !empty($numberOfGroups $dataset->getNumberOfGroups())) {
  106.                 for ($c 0$c $numberOfGroups$c++) {
  107.                     $dataline = new DataLine();
  108.                     $dataline->setConcentration(0);
  109.                     $dataline->setSubjects(0);
  110.                     $dataline->setIncidence(0);
  111.                     if ($dataset->getExposureType() === "several_durations") {
  112.                         $dataline->setTime(0);
  113.                     }
  114.                     $datalines->addDataLine($dataline);
  115.                 }
  116.                 $dataset->setDataLines($datalines);
  117.             }
  118.             return $this->redirectToRoute('bmdArray', ['datasetId' => $dataset->getId()]);
  119.         }
  120.         return $this->render('bmd.html.twig', [
  121.             'form' => $form->createView(),
  122.         ]);
  123.     }
  124.     /**
  125.      * @Route("/bmd/{datasetId}", name="bmdArray")
  126.      */
  127.     public function bmdArray(Request $request)
  128.     {
  129.         $session $request->getSession();
  130.         $dataset $session->get('dataset');
  131.         $datalines $dataset->getDataLines();
  132.         $session_id $request->getSession()->getId();
  133.         $upload_directory $this->getParameter('upload_directory');
  134.         $exposure_type $dataset->getExposureType();
  135.         $form $this->createForm(DataLinesType::class, $datalines);
  136.         $form->handleRequest($request);
  137.         if ($form->isSubmitted() && $form->isValid()) {
  138.             if ($exposure_type === 'several_durations') {
  139.                 $r_file 'bmd_plusieursDureesExpo_V2.r';
  140.                 $time $dataset->getExposureDuration();
  141.             } else {
  142.                 $r_file 'bmd_uneDureeExpo_V2.r';
  143.                 $dataset->getExposureDuration() ? $time $dataset->getExposureDuration() : $time "NA";
  144.             }
  145.             $user_folder $upload_directory '/' $session_id;
  146.             $plotParameters $dataset->getPlotParameters();
  147.             (in_array("plot_option_log_scale"$plotParameters)) ? $log_scale TRUE $log_scale FALSE;
  148.             (in_array("plot_option_error_bars"$plotParameters)) ? $error_bars TRUE $error_bars FALSE;
  149.             $replace = array(
  150.                 str_replace('\\''/''"' $user_folder '/"'),
  151.                 "NA",
  152.                 $dataset->getBmdExtrapolation() === true "TRUE" "FALSE",
  153.                 $log_scale === true "TRUE" "FALSE",
  154.                 $error_bars === true "TRUE" "FALSE",
  155.                 '"' implode(","$dataset->getBenchmarkResponse()) . '"',
  156.                 $time
  157.             );
  158.             //chemin d'acces à configurer une fois l'application mise sur le serveur
  159.             $template_r_file $this->getParameter('util_directory') . '/' $r_file;
  160.             $fp fopen($user_folder '/data.in''w');
  161.             $headers = array('concentration''subjects''incidence');
  162.             if ($exposure_type === 'several_durations'$headers[] = 'time';
  163.             fputcsv($fp$headers';');
  164.             foreach ($datalines->getDataLines() as $dataline) {
  165.                 $data = array($dataline->getConcentration(), $dataline->getSubjects(), $dataline->getIncidence());
  166.                 if ($exposure_type === 'several_durations'$data[] = $dataline->getTime();
  167.                 fputcsv($fp$data';');
  168.             }
  169.             fclose($fp);
  170.             ini_set('max_execution_time'600);
  171.             $stopwatch = new Stopwatch();
  172.             $target dirname(dirname(dirname(dirname(dirname(__FILE__)))));
  173.             $target .= 'tmp-perso\R-Portable\App\R-Portable\bin\R.exe';
  174.             if (strtoupper(substr(PHP_OS03)) === 'WIN') {
  175.                 $cmd '"' $target '" --vanilla --slave --args ' implode(" "$replace) . ' < ' $template_r_file;
  176.                 $stopwatch->start('RscriptExecution');
  177.                 exec($cmd);
  178.             } else {
  179.                 $stopwatch->start('RscriptExecution');
  180.                 //Rediriger la sortie standard vers /dev/null, puis rediriger la sortie d'erreur vers la sortie standard.
  181. //dump("cat " . $template_r_file . " | /opt/R/3.6.0/bin/R --vanilla --slave --args " . implode(" ", $replace) . " >/dev/null 2>&1");die;
  182. exec("cat " $template_r_file " | /opt/R/3.6.0/bin/R --vanilla --slave --args " implode(" "$replace) . " >/dev/null 2>&1");
  183.             }
  184.             while (!is_file($user_folder '/results.txt')) {
  185.                 continue;
  186.             }
  187.             $event $stopwatch->stop('RscriptExecution');
  188.             $session->set('timer'$event->getDuration());
  189.             //Enregistrement des executions dans un fichier de log
  190.             $file dirname(dirname(dirname(__FILE__))) . "/log.txt";
  191.             if (!file_exists($file)) touch($file);
  192.             $current file_get_contents($file);
  193.             $current .= "\n Script execute - " date("Y-m-d H:i:s");
  194.             file_put_contents($file$current);
  195.             return $this->redirectToRoute('resultsByUniqueId', ['datasetId' => $dataset->getId()]);
  196.         }
  197.         return $this->render('bmd_array.html.twig', [
  198.             'form' => $form->createView(),
  199.             'dataset' => $dataset,
  200.         ]);
  201.     }
  202.     /**
  203.      * @Route("/results/{datasetId}", name="resultsByUniqueId")
  204.      */
  205.     public function results(Request $requestTranslatorInterface $translator)
  206.     {
  207.         $session $request->getSession();
  208.         $dataset $session->get('dataset');
  209.         $session_id $request->getSession()->getId();
  210.         $upload_directory $this->getParameter('upload_directory');
  211.         $user_folder "$upload_directory/$session_id/";
  212.         $exposure_type $dataset->getExposureType();
  213.         $results_file $user_folder 'results.txt';
  214.         $warning_file $user_folder 'warnings.txt';
  215.         if (is_file($results_file)) {
  216.             $results = new Results();
  217.             $results->setDataset($dataset->getId());
  218.             $tab_result file($results_file);
  219.             for ($i 0$i count($tab_result); $i++) {
  220.                 $char[$i] = explode("\t"$tab_result[$i]);
  221.             }
  222.             if ($char[0][0] == '"slope"') {
  223.                 $results->setErrors(null);
  224.             } else {
  225.                 $results->setErrors(file_get_contents($results_file));
  226.             }
  227.             // en cas d'erreur dans le script R retour sur l'écran de saisie et affichage des erreurs
  228.             $error_list = [
  229.                 "Please check your data: There should be 3 columns named concentration, subjects, incidence",
  230.                 "Please check your data: all data should be numeric.",
  231.                 "Please check your data: number of data for dose, incidence, and subjects should be equal",
  232.                 "Please check your data and delete any line with missing data",
  233.                 "Exposure duration should be a number :",
  234.                 "Number of groups is not sufficient for log-probit modeling: there should be at least 3",
  235.                 "Incidence rate must be between 0 and 1",
  236.                 "There must be incidence rates strictly between 0 and 1",
  237.                 "Failed to estimate parameters: algorithm did not converge",
  238.                 "Please check your data: There should be 4 columns named concentration, subjects, incidence, time",
  239.                 "Please check your data: number of data for dose, incidence, subjects, and duration should be equal",
  240.                 "Number of groups is not sufficient for log-probit modeling",
  241.                 "All durations are equal: please select the 'One duration' option",
  242.                 "At least one of the exposure durations must be tested for several concentrations or at least one of the concentrations must be tested at several exposure durations",
  243.                 "There must be at least two incidence rates strictly between 0 and 1, for two different durations",
  244.             ];
  245.             if ($results->getErrors()) {
  246.                 $string $results->getErrors();
  247. $this->logger->error('Error found: ', [
  248.                     '$string' => $string,
  249.                 ]);
  250. $extracted_string "error";
  251.                 $first_colon_pos strpos($string':');
  252.                 if ($first_colon_pos !== false) {
  253.                     $extracted_string trim(substr($string$first_colon_pos 1));
  254.                 }
  255.                 // Check if $extracted_string matches any of the errors in $error_list
  256.                 $error_found false;
  257.                 foreach ($error_list as $error) {
  258.                     if (strpos($extracted_string$error) !== false) {
  259.                         $error_found true;
  260.                         break;
  261.                     }
  262.                 }
  263.                 $this->logger->error('Error found: ' $error, [
  264.                     'extracted_string' => $extracted_string,
  265.                 ]);
  266.                 if (!$error_found) {
  267.                     // Create a ZIP archive of all files in $user_folder
  268.                     $zip = new ZipArchive();
  269.                     $zip_filename "../data/files_$session_id.zip";
  270.                     if ($zip->open($zip_filenameZipArchive::CREATE ZipArchive::OVERWRITE) === true) {
  271.                         $files = new RecursiveIteratorIterator(
  272.                             new RecursiveDirectoryIterator($user_folder),
  273.                             RecursiveIteratorIterator::LEAVES_ONLY
  274.                         );
  275.                         foreach ($files as $name => $file) {
  276.                             if (!$file->isDir()) {
  277.                                 $filePath $file->getRealPath();
  278.                                 $relativePath substr($filePathstrlen($user_folder) + 1);
  279.                                 $zip->addFile($filePath$relativePath);
  280.                             }
  281.                         }
  282.                         $zip->close();
  283.                     }
  284.                     // Affichage d'une erreur générique
  285.                     $extracted_string $translator->trans('results.technical_error');
  286.                 }
  287.                 $this->addFlash('danger'$translator->trans('results.error') . $extracted_string $translator->trans('results.error_contact'));
  288.                 return $this->redirectToRoute('bmd');
  289.             }
  290.             if ($char[1][11] != 0) {
  291.                 $results->setConvergence("not converged " $char[1][11]);
  292.             } else {
  293.                 $results->setConvergence("converged");
  294.                 $results->setSlope(array($char[1][1], $char[1][2], $char[1][3]));
  295.                 $pictures = array();
  296.                 $scaledResiduals = array();
  297.                 $computations = array();
  298.                 if ($exposure_type === 'several_durations') {
  299.                     $results->setN(array($char[1][4], $char[1][5], $char[1][6]));
  300.                     $results->setIntercept(array($char[1][7], $char[1][8], $char[1][9]));
  301.                     array_push($picturesbase64_encode(file_get_contents(__DIR__ '/../../public/uploads/' $session_id '/plot_allT.jpg')));
  302.                     for ($i 1$i <= (($char[1][19]) * ($char[1][20])); $i++) {
  303.                         $plot_file $user_folder 'plot' $char[$i][13] . '_T' $char[$i][12] . '.jpg';
  304.                         if (@is_file($plot_file)) {
  305.                             array_push($picturesbase64_encode(file_get_contents(__DIR__ '/../../public/uploads/' $session_id '/plot' $char[$i][13] . '_T' $char[$i][12] . '.jpg')));
  306.                         }
  307.                     }
  308.                     $results->setMaxLog($char[1][10]);
  309.                     for ($i 1$i <= ($char[1][23]); $i++) {
  310.                         array_push($scaledResiduals$char[1][23 $i]);
  311.                     }
  312.                     $results->setChiSquare($char[1][21]);
  313.                     $results->setFitGoodness($char[1][18]);
  314.                     for ($i 1$i <= (($char[1][19]) * ($char[1][20])); $i++) {
  315.                         $computations[$i][] = $char[$i][13];
  316.                         $computations[$i][] = $char[$i][12];
  317.                         $computations[$i][] = $char[$i][14];
  318.                         $computations[$i][] = $char[$i][15];
  319.                         $computations[$i][] = $char[$i][17];
  320.                     }
  321.                 } else {
  322.                     $results->setN(null);
  323.                     $results->setIntercept(array($char[1][4], $char[1][5], $char[1][6]));
  324.                     for ($i 1$i <= $char[1][15]; $i++) {
  325.                         array_push($picturesbase64_encode(file_get_contents(__DIR__ '/../../public/uploads/' $session_id '/plot' $char[$i][13] . '.jpg')));
  326.                     }
  327.                     $results->setMaxLog($char[1][7]);
  328.                     for ($i 1$i <= ($char[1][33]); $i++) {
  329.                         array_push($scaledResiduals$char[1][33 $i]);
  330.                     }
  331.                     $results->setChiSquare($char[1][16]);
  332.                     $results->setFitGoodness($char[1][14]);
  333.                     for ($i 1$i <= $char[1][15]; $i++) {
  334.                         $computations[$i][] = $char[$i][13];
  335.                         $computations[$i][] = $char[$i][9];
  336.                         $computations[$i][] = $char[$i][10];
  337.                         $computations[$i][] = $char[$i][12];
  338.                     }
  339.                     $time $dataset->getExposureDuration();
  340.                     if (isset($time) && $dataset->getBmdExtrapolation() === true) {
  341.                         $duration = array(110203060120240480);
  342.                         $extrapolations = array();
  343.                         for ($i 1$i <= $char[1][15]; $i++) {
  344.                             foreach ($duration as $key => $value) {
  345.                                 $extrapolations[$i][$value][] = $char[$i][13];
  346.                                 $extrapolations[$i][$value][] = $value;
  347.                                 $extrapolations[$i][$value][] = $char[$i][$key 17];
  348.                                 $extrapolations[$i][$value][] = $char[$i][$key 25];
  349.                             }
  350.                         }
  351.                         $results->setBenchmarkDoseExtrapolation($extrapolations);
  352.                     }
  353.                 }
  354.                 $results->setPictures($pictures);
  355.                 $results->setScaledResiduals($scaledResiduals);
  356.                 $results->setBenchmarkDoseComputation($computations);
  357.             }
  358.             if (is_file($warning_file)) {
  359.                 $tab_warning file($warning_file);
  360.                 for ($i 0$i count($tab_warning); $i++) {
  361.                     $char2[$i] = explode("\t"$tab_warning[$i]);
  362.                 }
  363.                 $results->setWarnings(file_get_contents($warning_file));
  364.             }
  365.         } else {
  366.             $this->addFlash('danger'"Results file can not be obtained");
  367.         }
  368.         $pdfOptions = new Options();
  369.         $pdfOptions->setIsRemoteEnabled(true);
  370.         $pdfOptions->setDefaultFont("DejaVu Sans");
  371.         $dompdf = new Dompdf($pdfOptions);
  372.         $html $this->renderView('pdf.html.twig', [
  373.             'dataset' => $dataset,
  374.             'results' => $results,
  375.         ]);
  376.         $dompdf->loadHtml($html);
  377.         $dompdf->setPaper('A4''portrait');
  378.         $dompdf->render();
  379.         $output $dompdf->output();
  380.         $studyReference $dataset->getStudyReference() ? $dataset->getStudyReference() . '-' '';
  381.         $species $dataset->getSpecies() ? $dataset->getSpecies() . '-' '';
  382.         $filePath $user_folder '/PROBIT-BMD-' $studyReference $species;
  383.         file_put_contents($filePath 'results.pdf'$output);
  384.         file_put_contents($filePath 'data.txt'str_replace("\n""\r\n"file_get_contents($user_folder '/data.in')));
  385.         return $this->render('results.html.twig', [
  386.             'dataset' => $dataset,
  387.             'results' => $results,
  388.         ]);
  389.     }
  390.     /**
  391.      * @Route("/help", methods={"GET"}, name="help")
  392.      */
  393.     public function help()
  394.     {
  395.         return $this->render('help.html.twig');
  396.     }
  397. }