src/Controller/JobController.php line 156

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Carbon\Carbon;
  4. use App\Entity\Job;
  5. use ReflectionClass;
  6. use App\Entity\Import;
  7. use App\Entity\Snapshot;
  8. use App\Entity\MealPeriod;
  9. use App\Entity\ImportOrderSummary;
  10. use Psr\Container\ContainerInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Console\Input\ArrayInput;
  14. use Symfony\Component\Routing\Annotation\Route;
  15. use phpDocumentor\Reflection\DocBlock\Tags\Var_;
  16. use Symfony\Component\Console\Output\NullOutput;
  17. use Symfony\Component\HttpKernel\KernelInterface;
  18. use Symfony\Component\HttpFoundation\JsonResponse;
  19. use Symfony\Component\Console\Output\BufferedOutput;
  20. use Symfony\Bundle\FrameworkBundle\Console\Application;
  21. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  22. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  23. /**
  24.  * Class JobController
  25.  * @package App\Controller
  26.  */
  27. class JobController extends AbstractController
  28. {
  29.     /**
  30.      * @var int
  31.      */
  32.     public const LIMIT_JOB_EXECUTION_COUNT 3;
  33.     /**
  34.      * starts processing jobs in background process
  35.      * @throws \Exception
  36.      */
  37.     public static function triggerProcessingJobs(KernelInterface $kernel)
  38.     {
  39.         // trigger processing jobs
  40.         $application = new Application($kernel);
  41.         $application->setAutoExit(false);
  42.         $input = new ArrayInput([
  43.             'command' => 'app:process-jobs'
  44.         ]);
  45.         // You can use NullOutput() if you don't need the output
  46.         $output = new NullOutput();
  47.         $application->run($input$output);
  48.     }
  49.     /**
  50.      * @Route("/job/displayed", name="job_displayed")
  51.      * @IsGranted("ROLE_USER")
  52.      * @param \Symfony\Component\HttpFoundation\Request $request
  53.      * @return \Symfony\Component\HttpFoundation\JsonResponse
  54.      */
  55.     public function setJobDisplayed(Request $request): JsonResponse
  56.     {
  57.         $job_id $request->get("job_id"false);
  58.         if (!$job_id) {
  59.             return new JsonResponse([
  60.                 "result" => false,
  61.                 "message" => "No Job ID.",
  62.                 "data" => [],
  63.             ]);
  64.         }
  65.         $entityManager $this->getDoctrine()->getManager();
  66.         $job $entityManager->getRepository(Job::class)->find($job_id);
  67.         if (!preg_match("/_displayed$/"$job->getStatus())) {
  68.             $status $job->getStatus() . "_displayed";
  69.             $job->setStatus($status);
  70.             $job->setModified(new \DateTime());
  71.             $entityManager->persist($job);
  72.             $entityManager->flush();
  73.         }
  74.         return new JsonResponse([
  75.             "result" => true,
  76.             "message" => "Job set displayed successfully",
  77.             "data" => [],
  78.         ]);
  79.     }
  80.     /**
  81.      * @Route("/job/ready", name="job_ready")
  82.      * @IsGranted("ROLE_USER")
  83.      * @param Request $request
  84.      * @param \Symfony\Component\HttpKernel\KernelInterface $kernel
  85.      * @return JsonResponse
  86.      * @throws \Exception
  87.      */
  88.     public function getReadyJobs(Request $requestKernelInterface $kernel): JsonResponse
  89.     {
  90.         $user_id $request->get("user_id"false);
  91.         if (!$user_id) {
  92.             return new JsonResponse([
  93.                 "result" => false,
  94.                 "message" => "No User ID.",
  95.                 "data" => [],
  96.             ]);
  97.         }
  98.         $entityManager $this->getDoctrine()->getManager();
  99.         $jobs $entityManager->getRepository(Job::class)->findBy([
  100.             "created_by" => $user_id,
  101.             "status" => ["done""failed"],
  102.         ], [
  103.             "created" => "ASC",
  104.         ]);
  105.         $responseData = [];
  106.         foreach ($jobs as $job) {
  107.             $responseData[] = [
  108.                 "job_id" => $job->getId(),
  109.                 "job_url" => $job->getUrl(),
  110.                 "job_type" => $job->getType(),
  111.                 "job_status" => $job->getStatus(),
  112.                 "job_finished" => $job->getFinished()->getTimestamp(),
  113.             ];
  114.         }
  115.         JobController::triggerProcessingJobs($kernel);
  116.         return new JsonResponse([
  117.             "result" => true,
  118.             "message" => "Jobs loaded successfully",
  119.             "data" => $responseData,
  120.         ]);
  121.     }
  122.     /**
  123.      * @Route("/job/current", name="job_current")
  124.      * @IsGranted("ROLE_USER")
  125.      * @param Request $request
  126.      * @param KernelInterface $kernel
  127.      * @return JsonResponse
  128.      */
  129.     public function getByCurrentUser(Request $requestKernelInterface $kernel): JsonResponse
  130.     {
  131.         $user $this->getUser();
  132.         $user_role $user->getUserRole();
  133.         $project_id $request->get("project_id"false);
  134.         $import_id $request->get("import_id"false);
  135.         $entityManager $this->getDoctrine()->getManager();
  136.         # Get import order summary via entity manager
  137.         $importOrderSummary $entityManager->getRepository(ImportOrderSummary::class)->findBy(
  138.             array(
  139.                 "project_id" => $project_id,
  140.                 "import_id" => $import_id,
  141.             ),
  142.             array(
  143.                 "created" => "DESC"
  144.             )
  145.         );
  146.         $queryBuilder $entityManager->createQueryBuilder();
  147.         $snapshots $queryBuilder->select('s')
  148.             ->from(Snapshot::class, 's')
  149.             ->where('s.project_id = :project_id')
  150.             ->andWhere('s.import_id = :import_id');
  151.             $snapshots $snapshots->orderBy('s.created''DESC')
  152.             ->setParameters([
  153.                 'project_id' => $project_id,
  154.                 'import_id' => $import_id,
  155.             ])
  156.             ->getQuery()
  157.             ->getResult();
  158.         $filteredJobs = [];
  159.         foreach ($snapshots as $snapshot) {
  160.             if ($user_role == && $snapshot->getDeleted() == true) {
  161.                 continue;
  162.             }
  163.             $s_content unserialize(base64_decode($snapshot->getContent()));
  164.             $s_project $s_content["project"];
  165.             $s_project_id $s_content["project"]->getId();
  166.             $s_import $s_content["import"];
  167.             $s_import_id $s_content["import"]->getId();
  168.             
  169.             $s_type $s_content["snapshot_type"];
  170.             $s_category $s_content["category_selected"] ?? "";
  171.             $s_super_category $s_content["super_category_selected"] ?? "";
  172.             $s_meal_period $s_content["meal_period_selected"] ?? "";
  173.             
  174.             // http://localhost:2222/dashboard/overall?project_id=21&import_id=203
  175.             if ($s_content["snapshot_type"] == "overall") {
  176.                 // Generate hash params
  177.                 $getVars = [];
  178.                 $getVars["project_id"] = strval($s_project_id);
  179.                 $getVars["import_id"] = strval($s_import_id);
  180.             } else if ($s_content["snapshot_type"] == "details") {
  181.                 $s_super_category $s_content["super_category_selected"];
  182.                 $s_category $s_content["category_selected"];
  183.                 $s_meal_period_id $s_content["meal_period_id_selected"];
  184.                 $s_project_id strval($s_project_id);
  185.                 $s_import_id strval($s_import_id);
  186.                 $s_days $s_content["days"];
  187.                 // Generate hash params
  188.                 $getVars = [];
  189.                 $getVars["super_category"] = $s_super_category;
  190.                 $getVars["category"] = $s_category;
  191.                 $getVars["meal_period_id"] = $s_meal_period_id;
  192.                 $getVars["project_id"] = $s_project_id;
  193.                 $getVars["import_id"] = $s_import_id;
  194.                 if ($s_days["sunday"] != 0$getVars["sunday"] = $s_days["sunday"];
  195.                 if ($s_days["monday"] != 0$getVars["monday"] = $s_days["monday"];
  196.                 if ($s_days["tuesday"] != 0$getVars["tuesday"] = $s_days["tuesday"];
  197.                 if ($s_days["wednesday"] != 0$getVars["wednesday"] = $s_days["wednesday"];
  198.                 if ($s_days["thursday"] != 0$getVars["thursday"] = $s_days["thursday"];
  199.                 if ($s_days["friday"] != 0$getVars["friday"] = $s_days["friday"];
  200.                 if ($s_days["saturday"] != 0$getVars["saturday"] = $s_days["saturday"];
  201.             }
  202.             
  203.             // We need to get the import from the database, because the import in the snapshot is not the same as the one in the database
  204.             $currentImport $entityManager->getRepository(Import::class)->find($s_import_id);
  205.             $currentImportOrderSummary $entityManager->getRepository(ImportOrderSummary::class)->findBy([
  206.                 "project_id" => $s_project_id,
  207.                 "import_id" => $s_import_id,
  208.             ]);
  209.             
  210.             $currentHashParams hash("sha256"serialize([$getVars$currentImport$currentImportOrderSummary]));
  211.             $currentHashParams2 $currentHashParams;
  212.             if ($s_content["snapshot_type"] == "details") {
  213.                 /*
  214.                     We kind of need this extra variable to make sure the hash is the same as the one in the snapshot - sometimes?
  215.                     For know we accept both with and without the submit-form-button as unchanged.
  216.                     Maybe we can remove this in the future and always include this (at line 229).
  217.                 */
  218.                 
  219.                 $getVars["submit-form-button"] = "";
  220.                 $currentHashParams2 hash("sha256"serialize([$getVars$currentImport$currentImportOrderSummary]));
  221.             }
  222.             $s_hash $snapshot->getHash();
  223.             $s_hashParams $snapshot->getHashParams();
  224.             $s_startDate $s_content["import"]->getStartDate();
  225.             $s_endDate $s_content["import"]->getEndDate();
  226.             $s_startDateAnalysis $s_content["import"]->getStartDateAnalysis();
  227.             $s_endDateAnalysis $s_content["import"]->getEndDateAnalysis();
  228.             $s_overheadCosts $s_content["import"]->getOverheadCosts(); // Betriebskoste
  229.             $s_CogsNet $s_content["import"]->getDefaultCogsNet(); // Wareneinsat
  230.             $s_categories $s_content["categories"];
  231.             $s_days $s_content["days"];
  232.             $s_snapshot_type $s_content["snapshot_type"];
  233.             $_deleted $snapshot->getDeleted();
  234.             $s_baseUrl $request->getSchemeAndHttpHost() . $request->getBaseUrl();
  235.             $softChange = ($s_import->getOverheadCosts() != $s_overheadCosts
  236.                         || $s_import->getStartDate() != $s_startDate
  237.                         || $s_import->getEndDate() != $s_endDate
  238.                         || $s_import->getStartDateAnalysis() != $s_startDateAnalysis
  239.                         || $s_import->getEndDateAnalysis() != $s_endDateAnalysis
  240.                         || $s_import->getDefaultCogsNet() != $s_CogsNet);
  241.             
  242.             $changed = ($currentHashParams != $s_hashParams && $currentHashParams2 != $s_hashParams) ? "outdated" "";
  243.             Carbon::setLocale('de');
  244.             $outdatedParams = [
  245.                 "Overhead costs" => ($currentImport->getOverheadCosts() != $s_overheadCosts) ? $s_overheadCosts false,
  246.                 "Startdate of Import" => ($currentImport->getStartDate() != $s_startDate) ? Carbon::parse($s_startDate->date)->toDateTimeString() : false,
  247.                 "EndDate of Import" => ($currentImport->getEndDate() != $s_endDate) ? Carbon::parse($s_endDate->date)->toDateTimeString() : false,
  248.                 "Startdate of Analysis" => ($currentImport->getStartDateAnalysis() != $s_startDateAnalysis) ? Carbon::parse($s_startDateAnalysis->date)->toDateTimeString() : false,
  249.                 "Enddate of Analysis" => ($currentImport->getEndDateAnalysis() != $s_endDateAnalysis) ? Carbon::parse($s_endDateAnalysis->date)->toDateTimeString() : false,
  250.                 "Default Cogs net" => ($currentImport->getDefaultCogsNet() != $s_CogsNet) ? $s_CogsNet false,
  251.             ];
  252.             $outdatedParamsString "";
  253.             $outdatedParamsArray array_filter($outdatedParams, function($value) {
  254.                 return $value === true;
  255.             });
  256.             if (!empty($outdatedParamsArray)) {
  257.                 $outdatedParamsString implode(", "array_keys($outdatedParamsArray));
  258.             }
  259.             // $viewData = array(
  260.             //     "project" => $project,
  261.             //     "import" => $import,
  262.             //     "cash_system" => $cash_system,
  263.             //     "meal_periods" => $meal_periods,
  264.             //     "categories" => $categories,
  265.             //     "analysis_data" => $analysis_data,
  266.             //     "analysis_data_charts" => $analysis_data_charts,
  267.             //     "kpis_total" => $kpis_total,
  268.             //     "pie_chart_data" => $pie_chart_data,
  269.             //     "column_chart_data" => $column_chart_data,
  270.             //     "notice" => $notice,
  271.             //     "snapshot" => false,
  272.             //     "snapshot_id" => false,
  273.             //     "snapshots" => [],
  274.             //     "snapshot_contents" => [],
  275.             //     "snapshot_type" => "overall",
  276.             //     "currency" => $currency,
  277.             //     "days" => $days,
  278.             // );
  279.             $d $snapshot->getCreated()->format("d.m.Y H:i:s");
  280.             $newJob["id"] = 1;
  281.             //$newJob["url"] = "$s_baseUrl/dashboard/$s_type?project_id=$s_project_id&import_id=$s_import_id";
  282.             $newJob["url"] = "$s_baseUrl/dashboard/$s_type?hash=$s_hash";
  283.             $newJob["hash"] = $s_hash;
  284.             $newJob["date"] = date("d.m.Y"strtotime($d) );
  285.             $newJob["time"] = date("H:i:s"strtotime($d) );
  286.             $newJob["type"] = $s_snapshot_type;
  287.             $newJob["status"] = $changed;
  288.             $newJob["outdatedParams"] = $outdatedParams;
  289.             $newJob["days"] = $s_days;
  290.             $newJob["importname"] = $s_import->getDescription();
  291.             $newJob["category"] = $s_category;
  292.             $newJob["super_category"] = $s_super_category;
  293.             $newJob["meal_period"] = $s_meal_period;
  294.             $newJob["project_id"] = $s_project_id;
  295.             $newJob["import_id"] = $s_import_id;
  296.             $newJob["deleted"] = $_deleted;
  297.             // $newJob["meal_period"] = $s_meal_period_name;
  298.             $filteredJobs[] = $newJob;
  299.         }
  300.         return new JsonResponse([
  301.             "result" => true,
  302.             "message" => "Jobs loaded successfully",
  303.             "data" => $filteredJobs,
  304.         ]);
  305.     }
  306.     /**
  307.      * @Route("/job/process", name="job_process")
  308.      * @param Request $request
  309.      * @param \Symfony\Component\HttpKernel\KernelInterface $kernel
  310.      * @return Response
  311.      * @throws \Exception
  312.      */
  313.     public function process(Request $requestKernelInterface $kernel): Response
  314.     {
  315.         $entityManager $this->getDoctrine()->getManager();
  316.         // don't do anything if a job is running already
  317.         $runningJobs $entityManager->getRepository(Job::class)->findBy([
  318.             "status" => "processing"
  319.         ]);
  320.         $now Carbon::now();
  321.         $freedJobs 0;
  322.         foreach ($runningJobs as $j) {
  323.             // It is possible that jobs get "stuck". if a Jobs is longer then 1 Minute on "processing",
  324.             // set the status to "notfinished".
  325.             $startet Carbon::parse($j->getCreated());
  326.             if ($now->diffInSeconds($startet) > 60) {
  327.                 $crashedJob $entityManager->getRepository(Job::class)->find($j->getId());
  328.                 $crashedJob->setStatus("notfinished.");
  329.                 $crashedJob->setModified(new \DateTime());
  330.                 $entityManager->persist($crashedJob);
  331.                 $entityManager->flush();
  332.                 $freedJobs++;
  333.             }
  334.         }
  335.         if (count($runningJobs) - $freedJobs >= self::LIMIT_JOB_EXECUTION_COUNT) {
  336.             return new Response("The maximum number of jobs is already running.");
  337.         }
  338.         $nextJob $entityManager->getRepository(Job::class)->findOneBy([
  339.             "status" => "queued"
  340.         ], [
  341.             "created" => "ASC"
  342.         ]);
  343.         if (!$nextJob) {
  344.             return new Response("Nothing to do.");
  345.         }
  346.         if ($nextJob->getType() == "details") {
  347.             $response $this->forward('App\Controller\SnapshotController::createDetails', ["job_id" => $nextJob->getId(),"job_token" => $this->getParameter("job_token")]);
  348.         } else { //if ($nextJob->getType() == "overall") {
  349.             $response $this->forward('App\Controller\SnapshotController::createOverall', ["job_id" => $nextJob->getId(),"job_token" => $this->getParameter("job_token")]);
  350.         }
  351.         if ($response->getContent() == "failed") {
  352.             // var_dump($response);
  353.         } else {
  354.         }
  355.         if(!isset($jobResponse)) { //In case of triggered by cronjob
  356.             die();
  357.         } else {
  358.             // if we get here there are maybe further jobs to be processed, so let's trigger them
  359.             JobController::triggerProcessingJobs($kernel);
  360.             return new Response("Processed job id " $nextJob->getId() . ", result: " $response->getContent());
  361.         }
  362.     }
  363. }