src/Services/LogTools.php line 31

Open in your IDE?
  1. <?php
  2. //----------------------------------------------------------------------
  3. // src/Services/LogTools.php
  4. //----------------------------------------------------------------------
  5. namespace App\Services;
  6. use DateTime;
  7. use Doctrine\Persistence\ManagerRegistry;
  8. use Psr\Log\LoggerInterface;
  9. use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
  10. use Symfony\Contracts\Translation\TranslatorInterface;
  11. use Symfony\Component\Security\Core\Security;
  12. use App\DTO\Log\LogCsvRecord;
  13. use App\Entity\Access;
  14. use App\Entity\AccessClient\AccessClient;
  15. use App\Entity\APIRest\AccessAPI;
  16. use App\Entity\Client\Client;
  17. use App\Entity\HR\HumanResource;
  18. use App\Entity\Ikea\ServiceOrder;
  19. use App\Entity\Mission\Mission;
  20. use App\Entity\OnlinePayment\PaymentType as OnlinePaymentType;
  21. use App\Entity\Planning\Task;
  22. use App\Entity\Platform\Devis\Devis;
  23. use App\Entity\Platform\Invoice\Invoice;
  24. use App\Entity\ProjectManager\ProjectNotebook;
  25. use App\Entity\SocietyGroup;
  26. class LogTools
  27. {
  28.     public function __construct(ManagerRegistry $doctrineTranslatorInterface $translatorLoggerInterface $ouchLoggerSecurity $security)
  29.     {
  30.         $this->em $doctrine->getManager();
  31.         $this->translator $translator;
  32.         $this->security $security;
  33.         $this->ouchLogger $ouchLogger;
  34.     }
  35.     public function getRootDir()
  36.     {
  37.         $home dirname(__FILE__3);
  38.         return $home;
  39.     }
  40.     public function getPublicDir()
  41.     {
  42.         $home dirname(__FILE__3);
  43.         $home .= "/public/";
  44.         return $home;
  45.     }
  46.     public function getCustomLogsDir()
  47.     {
  48.         $home dirname(__FILE__3);
  49.         $home .= "/custom_logs/";
  50.         return $home;
  51.     }
  52.     public function getCustomDataDir()
  53.     {
  54.         $home dirname(__FILE__3);
  55.         $home .= "/custom_data/";
  56.         return $home;
  57.     }
  58.     public function getDMSRootDir()
  59.     {
  60.         $home dirname(__FILE__3);
  61.         $home .= "/DMS/";
  62.         return $home;
  63.     }
  64.     // Plan.io Task #4661
  65.     // ROOT/DMS/Ikea/logs/{society_group_id}/
  66.     public function getIkeaDMSLogsFolder(SocietyGroup $societyGroup)
  67.     {
  68.         $home $this->getDMSRootDir();
  69.         if (!is_dir($home))    $do mkdir($home0755true);
  70.         $home .= "Ikea/logs/";
  71.         if (!is_dir($home))    $do mkdir($home0755true);
  72.         $home .= $societyGroup->getId();
  73.         $home .= "/";
  74.         if (!is_dir($home))    $do mkdir($home0755true);
  75.         return $home;
  76.     }
  77.     // Plan.io Task #4661
  78.     // ROOT/DMS/Ikea/logs/{society_group_id}/
  79.     public function getIkeaDMSLogFile(ServiceOrder $serviceOrder)
  80.     {
  81.         if ($serviceOrder->getSocietyGroup() !== null)
  82.         {
  83.             $path $this->getIkeaDMSLogsFolder($serviceOrder->getSocietyGroup());
  84.             $logFile $path $serviceOrder->getId() . ".log";
  85.             return $logFile;
  86.         }
  87.         return null;
  88.     }
  89.     // Plan.io Task #4661
  90.     public function logNewXml(ServiceOrder $serviceOrderstring $data)
  91.     {
  92.         $logFile $this->getIkeaDMSLogFile($serviceOrder);
  93.         if ($logFile !== null)
  94.         {
  95.             $today = new \DateTime();
  96.             $timestamp $today->format("Y-m-d H:i:s");
  97.             error_log("\n[$timestamp$data"3$logFile);
  98.         }
  99.     }
  100.     // Plan.io Task #4448    
  101.     // ROOT/DMS/IkeaBP/logs/{society_group_id}/
  102.     public function getIkeaBpFolder(SocietyGroup $societyGroup)
  103.     {
  104.         $home $this->getDMSRootDir();
  105.         if (!is_dir($home))    $do mkdir($home0755true);
  106.         $home .= "IkeaBP/logs/";
  107.         if (!is_dir($home))    $do mkdir($home0755true);
  108.         $home .= $societyGroup->getId();
  109.         $home .= "/";
  110.         if (!is_dir($home))    $do mkdir($home0755true);
  111.         return $home;
  112.     }
  113.     public function getIkeaBpLogFileName(SocietyGroup $societyGroup)
  114.     {        
  115.         $today = new \DateTime();
  116.         $timestamp $today->format("Ymd_His");
  117.         $logFileName "IkeaBP_".$societyGroup->getId()."_".$timestamp.".log";
  118.         return $logFileName;
  119.     }
  120.     public function getIkeaBpErrorFileName(SocietyGroup $societyGroup)
  121.     {        
  122.         $today = new \DateTime();
  123.         $timestamp $today->format("Ymd_His");
  124.         $logFileName "IkeaBP_".$societyGroup->getId()."_".$timestamp.".err";
  125.         return $logFileName;
  126.     }
  127.     public function getIkeaBpLogFile(SocietyGroup $societyGroup)
  128.     {
  129.         $path $this->getIkeaBpFolder($societyGroup);        
  130.         $logFileName $this->getIkeaBpLogFileName($societyGroup);
  131.         $logFile $path.$logFileName;
  132.         return $logFile;
  133.     }
  134.     public function getIkeaBpErrorFile(SocietyGroup $societyGroup)
  135.     {
  136.         $path $this->getIkeaBpFolder($societyGroup);        
  137.         $logFileName $this->getIkeaBpErrorFileName($societyGroup);
  138.         $logFile $path.$logFileName;
  139.         return $logFile;
  140.     }
  141.     public function logToBpFile_andTask($logFileTask $task$msg)
  142.     {
  143.         $today = new \DateTime();
  144.         $timestamp $today->format("Y-m-d H:i:s");
  145.         error_log("\n[$timestamp$msg"3$logFile);
  146.         $ikeaBpProcessInfo $task->getIkeaBpProcessInfo();
  147.         $ikeaBpProcessInfo .= $msg;
  148.         $task->setIkeaBpProcessInfo($ikeaBpProcessInfo);
  149.         
  150.         // error_log("\n[$timestamp] $msg", 3, "ploop.log");
  151.     }
  152.     public function logToBpFile($logFile$msg)
  153.     {
  154.         $today = new \DateTime();
  155.         $timestamp $today->format("Y-m-d H:i:s");
  156.         error_log("\n[$timestamp$msg"3$logFile);
  157.         
  158.         // error_log("\n[$timestamp] $msg", 3, "ploop.log");
  159.     }
  160.     // ROOT/DMS/Export/CostAccount/society_group_id/
  161.     public function getCostAutoAccountExportFolder($societyGroup null)
  162.     {
  163.         $home $this->getDMSRootDir();
  164.         if (!is_dir($home))    $do mkdir($home0755true);
  165.         $home .= "Export/";
  166.         if (!is_dir($home))    $do mkdir($home0755true);
  167.         $home .= "CostAccount/";
  168.         if (!is_dir($home))    $do mkdir($home0755true);
  169.         if ($societyGroup !== null)
  170.         {
  171.             $home .= $societyGroup->getId();
  172.             $home .= "/";
  173.             if (!is_dir($home))    $do mkdir($home0755true);
  174.         }
  175.         return $home;
  176.     }
  177.     
  178.     // ROOT/DMS/Export/CostAccount/society_group_id/logs/
  179.     public function getCostAutoAccountExportLogsFolder(SocietyGroup $societyGroup)
  180.     {
  181.         $home $this->getDMSRootDir();
  182.         if (!is_dir($home))    $do mkdir($home0755true);
  183.         $home .= "Export/";
  184.         if (!is_dir($home))    $do mkdir($home0755true);
  185.         $home .= "CostAccount/";
  186.         if (!is_dir($home))    $do mkdir($home0755true);
  187.         $home .= $societyGroup->getId();
  188.         $home .= "/";
  189.         if (!is_dir($home))    $do mkdir($home0755true);
  190.         $home .= "logs/";
  191.         if (!is_dir($home))    $do mkdir($home0755true);
  192.         return $home;
  193.     }
  194.     
  195.     // ROOT/DMS/Export/InvoiceAccount/society_group_id/
  196.     public function getInvoiceAutoAccountExportFolder($societyGroup null)
  197.     {
  198.         $home $this->getDMSRootDir();
  199.         if (!is_dir($home))    $do mkdir($home0755true);
  200.         $home .= "Export/";
  201.         if (!is_dir($home))    $do mkdir($home0755true);
  202.         $home .= "InvoiceAccount/";
  203.         if (!is_dir($home))    $do mkdir($home0755true);
  204.         if ($societyGroup !== null)
  205.         {
  206.             $home .= $societyGroup->getId();
  207.             $home .= "/";
  208.             if (!is_dir($home))    $do mkdir($home0755true);
  209.         }
  210.         return $home;
  211.     }
  212.     
  213.     // ROOT/DMS/Export/InstallmentAccount/society_group_id/
  214.     public function getInstallmentAutoAccountExportFolder($societyGroup null)
  215.     {
  216.         $home $this->getDMSRootDir();
  217.         if (!is_dir($home))    $do mkdir($home0755true);
  218.         $home .= "Export/";
  219.         if (!is_dir($home))    $do mkdir($home0755true);
  220.         $home .= "InstallmentAccount/";
  221.         if (!is_dir($home))    $do mkdir($home0755true);
  222.         if ($societyGroup !== null)
  223.         {
  224.             $home .= $societyGroup->getId();
  225.             $home .= "/";
  226.             if (!is_dir($home))    $do mkdir($home0755true);
  227.         }
  228.         return $home;
  229.     }
  230.     
  231.     // ROOT/DMS/Export/InstallmentAccount/society_group_id/logs/
  232.     public function getInstallmentAutoAccountExportLogsFolder(SocietyGroup $societyGroup)
  233.     {
  234.         $home $this->getDMSRootDir();
  235.         if (!is_dir($home))    $do mkdir($home0755true);
  236.         $home .= "Export/";
  237.         if (!is_dir($home))    $do mkdir($home0755true);
  238.         $home .= "InstallmentAccount/";
  239.         if (!is_dir($home))    $do mkdir($home0755true);
  240.         $home .= $societyGroup->getId();
  241.         $home .= "/";
  242.         if (!is_dir($home))    $do mkdir($home0755true);
  243.         $home .= "logs/";
  244.         if (!is_dir($home))    $do mkdir($home0755true);
  245.         return $home;
  246.     }
  247.     
  248.     // ROOT/DMS/Export/InvoiceAccount/society_group_id/logs/
  249.     public function getInvoiceAutoAccountExportLogsFolder(SocietyGroup $societyGroup)
  250.     {
  251.         $home $this->getDMSRootDir();
  252.         if (!is_dir($home))    $do mkdir($home0755true);
  253.         $home .= "Export/";
  254.         if (!is_dir($home))    $do mkdir($home0755true);
  255.         $home .= "InvoiceAccount/";
  256.         if (!is_dir($home))    $do mkdir($home0755true);
  257.         $home .= $societyGroup->getId();
  258.         $home .= "/";
  259.         if (!is_dir($home))    $do mkdir($home0755true);
  260.         $home .= "logs/";
  261.         if (!is_dir($home))    $do mkdir($home0755true);
  262.         return $home;
  263.     }
  264.     /**
  265.      * Exports Logs to ROOT/DMS/Export/InvoiceAccount/society_group_id/logs/
  266.      * File Name : { yyyymmdd }_Export_QCompta_error.log
  267.      */
  268.     public function logError_invoiceAutoAccount(SocietyGroup $societyGroup$error)
  269.     {
  270.         $exportPath $this->getInvoiceAutoAccountExportLogsFolder($societyGroup);
  271.         $today = new \DateTime();
  272.         $ymd $today->format("Ymd");
  273.         $timestamp $today->format("Y-m-d H:i:s");
  274.         $fileName $ymd."_Export_QCompta_Factures_error".".log";
  275.         $errorFile $exportPath.$fileName;
  276.         error_log("\n[$timestamp$error"3$errorFile);
  277.     }
  278.     /**
  279.      * Exports Logs to ROOT/DMS/Export/CostAccount/society_group_id/logs/
  280.      * File Name : { yyyymmdd }_Export_Achats_QCompta_error.log
  281.      */
  282.     public function logError_costAutoAccount(SocietyGroup $societyGroup$error)
  283.     {
  284.         $exportPath $this->getCostAutoAccountExportLogsFolder($societyGroup);
  285.         $today = new \DateTime();
  286.         $ymd $today->format("Ymd");
  287.         $timestamp $today->format("Y-m-d H:i:s");
  288.         $fileName $ymd."_Export_QCompta_Achats_error".".log";
  289.         $errorFile $exportPath.$fileName;
  290.         error_log("\n[$timestamp$error"3$errorFile);
  291.     }
  292.     /**
  293.      * Exports Logs to ROOT/DMS/Export/InstallmentAccount/society_group_id/logs/
  294.      * File Name : { yyyymmdd }_Export_Reglements_QCompta_error.log
  295.      */
  296.     public function logError_installmentAutoAccount(SocietyGroup $societyGroup$error)
  297.     {
  298.         $exportPath $this->getInstallmentAutoAccountExportLogsFolder($societyGroup);
  299.         $today = new \DateTime();
  300.         $ymd $today->format("Ymd");
  301.         $timestamp $today->format("Y-m-d H:i:s");
  302.         $fileName $ymd."_Export_QCompta_Reglements_error".".log";
  303.         $errorFile $exportPath.$fileName;
  304.         error_log("\n[$timestamp$error"3$errorFile);
  305.     }
  306.     //--------------------------------------------------------------------------
  307.     // TO BE USED IN COMMANDS (OneShot) ONLY
  308.     //--------------------------------------------------------------------------
  309.     public function getCommandLogsDir()
  310.     {
  311.         $home $this->getCustomLogsDir()."command_logs/";
  312.         return $home;
  313.     }
  314.     public function command_log($filename$msg$newLine true)
  315.     {
  316.         $home $this->getCommandLogsDir();
  317.         $logFile $home $filename;
  318.         if ($newLine)
  319.             $msg "\n".$msg;
  320.         error_log($msg,3,$logFile);
  321.     }
  322.     //--------------------------------------------------------------------------
  323.     public function plooplog($msg)
  324.     {
  325.         error_log("\n".$msg."\n",3,"ploop.log");
  326.     }
  327.     // public function ploopWrite($msg)
  328.     // {
  329.     //     $filename = "ploop.log";
  330.     //     $msg = "\n".$msg."\n";
  331.     //     if (is_writable($filename)) 
  332.     //     {
  333.     //         if ($fp = fopen($filename, 'a')) 
  334.     //         {
  335.     //             fwrite($fp, $msg);
  336.     //         }
  337.     //     }        
  338.     // }
  339.     public function ploop_debug($active$msg)
  340.     {
  341.         if (!$active)
  342.             return false;
  343.         error_log("\n".$msg."\n",3,"ploop.log");
  344.     }
  345.     public function getGuardConfigDir()
  346.     {
  347.         $home $this->getRootDir();
  348.         $home .= "/src/Guardian/config/";
  349.         return $home;
  350.     }
  351.     public function getPlanningOptimisationLogsDir()
  352.     {
  353.         $home $this->getCustomLogsDir()."planning_optimisation_logs/";
  354.         return $home;
  355.     }
  356.     public function getIkeaKitchenPlannerLogsDir()
  357.     {
  358.         $home $this->getCustomLogsDir()."ikea_kitchen_planner_logs/";
  359.         return $home;
  360.     }
  361.     public function getApiIcodLogsDir()
  362.     {
  363.         $home $this->getCustomLogsDir()."api_icod/";
  364.         return $home;
  365.     }
  366.     public function getCynclyLogsDir()
  367.     {
  368.         $home $this->getCustomLogsDir()."cyncly_logs/";
  369.         return $home;
  370.     }
  371.     // NOTE: This folder is used for WIP subscription system not for the onlinePayment one
  372.     public function getStripeLogsDir()
  373.     {
  374.         $home $this->getCustomLogsDir()."stripe/";
  375.         return $home;
  376.     }
  377.     public function getGuestSuiteLogsDir()
  378.     {
  379.         $home $this->getCustomLogsDir()."guest_suite_log/";
  380.         return $home;
  381.     }
  382.     public function getGuardLogsDir()
  383.     {
  384.         $home $this->getCustomLogsDir()."guard_logs/";
  385.         return $home;
  386.     }
  387.     public function getGuardGlobalLogsDir()
  388.     {
  389.         $home $this->getCustomLogsDir()."guard_logs/global/";
  390.         return $home;
  391.     }
  392.     public function getIkeaOSLogsDir()
  393.     {
  394.         $home $this->getCustomLogsDir()."ikea_os_logs/";
  395.         return $home;
  396.     }
  397.     public function getIkeaOS_statusLogsDir()
  398.     {
  399.         $home $this->getCustomLogsDir()."ikea_os_logs/status_logs/";
  400.         return $home;
  401.     }
  402.     public function getIkeaHotlineCallLogsDir(SocietyGroup $societyGroup): string
  403.     {
  404.         $home $this->getCustomLogsDir()."ikea_hotline_call/";
  405.         if (!is_dir($home))
  406.         {
  407.             mkdir($home0755true);
  408.         }
  409.         $home .= $societyGroup->getId()."/";
  410.         if (!is_dir($home))
  411.         {
  412.             mkdir($home0755true);
  413.         }
  414.         return $home;
  415.     }
  416.     public function getIkeaSendLogsDir($societyGroup)
  417.     {
  418.         $home $this->getCustomLogsDir();
  419.         $home .= "ikea_send_logs/";
  420.         if (!is_dir($home))
  421.         {
  422.             $do mkdir($home0755true);
  423.             if ($do === false)
  424.             {
  425.                 return null;
  426.             }
  427.         }
  428.         if ($societyGroup !== null)
  429.         {
  430.             $id $societyGroup->getId();
  431.             $home .= $id."/";
  432.             if (!is_dir($home))
  433.             {
  434.                 $do mkdir($home0755true);
  435.                 if ($do === false)
  436.                 {
  437.                     $this->errorLog("Folder $home cannot be created.");
  438.                     return null;
  439.                 }
  440.             }
  441.         }
  442.         return $home;
  443.     }
  444.     
  445.     public function getPlanningLogsDir()
  446.     {
  447.         $home $this->getCustomLogsDir()."planning/";
  448.         if (!is_dir($home))    $do mkdir($home0755true);
  449.         return $home;
  450.     }
  451.     
  452.     public function getCostLogsDir()
  453.     {
  454.         $home $this->getCustomLogsDir()."cost_logs/";
  455.         if (!is_dir($home))    $do mkdir($home0755true);
  456.         return $home;
  457.     }
  458.     
  459.     public function getInstallmentLogsDir()
  460.     {
  461.         $home $this->getCustomLogsDir()."installment_logs/";
  462.         if (!is_dir($home))    $do mkdir($home0755true);
  463.         return $home;
  464.     }
  465.     
  466.     public function getInvoiceLogsDir()
  467.     {
  468.         $home $this->getCustomLogsDir()."invoice_logs/";
  469.         if (!is_dir($home))    $do mkdir($home0755true);
  470.         return $home;
  471.     }
  472.     
  473.     // custom_logs/invoice_logs/missing_devis_product/
  474.     public function getInvoiceMissingDevisProductsLogsDir()
  475.     {
  476.         $home $this->getInvoiceLogsDir();
  477.         $home .= "missing_devis_product/";
  478.         if (!is_dir($home))
  479.         {
  480.             $do mkdir($home0755true);
  481.             if ($do === false)
  482.             {
  483.                 return null;
  484.             }
  485.         }
  486.         return $home;
  487.     }
  488.     
  489.     // custom_logs/cost_logs/export/{society_group_id}/
  490.     public function getCostExportLogsDir($societyGroup)
  491.     {
  492.         $home $this->getCostLogsDir();
  493.         $home .= "export/";
  494.         if (!is_dir($home))
  495.         {
  496.             $do mkdir($home0755true);
  497.             if ($do === false)
  498.             {
  499.                 return null;
  500.             }
  501.         }
  502.         if ($societyGroup !== null)
  503.         {
  504.             $id $societyGroup->getId();
  505.             $home .= $id."/";
  506.             if (!is_dir($home))
  507.             {
  508.                 $do mkdir($home0755true);
  509.                 if ($do === false)
  510.                 {
  511.                     $this->errorLog("Folder $home cannot be created.");
  512.                     return null;
  513.                 }
  514.             }
  515.         }
  516.         return $home;
  517.     }
  518.     
  519.     // custom_logs/installment_logs/export/{society_group_id}/
  520.     public function getInstallmentExportLogsDir($societyGroup)
  521.     {
  522.         $home $this->getInstallmentLogsDir();
  523.         $home .= "export/";
  524.         if (!is_dir($home))
  525.         {
  526.             $do mkdir($home0755true);
  527.             if ($do === false)
  528.             {
  529.                 return null;
  530.             }
  531.         }
  532.         if ($societyGroup !== null)
  533.         {
  534.             $id $societyGroup->getId();
  535.             $home .= $id."/";
  536.             if (!is_dir($home))
  537.             {
  538.                 $do mkdir($home0755true);
  539.                 if ($do === false)
  540.                 {
  541.                     $this->errorLog("Folder $home cannot be created.");
  542.                     return null;
  543.                 }
  544.             }
  545.         }
  546.         return $home;
  547.     }
  548.     
  549.     // custom_logs/invoice_logs/export/{society_group_id}/
  550.     public function getInvoiceExportLogsDir(?SocietyGroup $societyGroup)
  551.     {
  552.         $home $this->getInvoiceLogsDir();
  553.         $home .= "export/";
  554.         if (!is_dir($home))
  555.         {
  556.             $do mkdir($home0755true);
  557.             if ($do === false)
  558.             {
  559.                 return null;
  560.             }
  561.         }
  562.         if ($societyGroup !== null)
  563.         {
  564.             $id $societyGroup->getId();
  565.             $home .= $id."/";
  566.             if (!is_dir($home))
  567.             {
  568.                 $do mkdir($home0755true);
  569.                 if ($do === false)
  570.                 {
  571.                     $this->errorLog("Folder $home cannot be created.");
  572.                     return null;
  573.                 }
  574.             }
  575.         }
  576.         return $home;
  577.     }
  578.     public function getITaskBaseLogsDir()
  579.     {
  580.         $home $this->getCustomLogsDir()."itask_logs/";
  581.         return $home;
  582.     }
  583.     public function getITaskLogsDir($societyGroup null)
  584.     {
  585.         $home $this->getITaskBaseLogsDir() . "auto/";
  586.         if ($societyGroup !== null)
  587.         {
  588.             $id $societyGroup->getId();
  589.             $home .= $id."/";
  590.             if (!is_dir($home))
  591.             {
  592.                 $do mkdir($home0755true);
  593.                 if ($do === false)
  594.                 {
  595.                     $this->errorLog("Folder $home cannot be created.");
  596.                     return null;
  597.                 }
  598.             }
  599.         }
  600.         return $home;
  601.     }
  602.     public function getITaskDebugDir()
  603.     {
  604.         $home $this->getITaskBaseLogsDir()."debug/";
  605.         return $home;
  606.     }
  607.     public function getLoginLogsDir()
  608.     {
  609.         $home $this->getCustomLogsDir()."login_logs/";
  610.         return $home;
  611.     }
  612.     public function getProductLogsDir()
  613.     {
  614.         $home $this->getCustomLogsDir()."product_logs/";
  615.         return $home;
  616.     }
  617.     public function getChargeLogsDir()
  618.     {
  619.         $home $this->getCustomLogsDir()."charge_logs/";
  620.         return $home;
  621.     }
  622.     public function getSmsLogsDir()
  623.     {
  624.         $home $this->getCustomLogsDir()."sms_logs/";
  625.         return $home;
  626.     }
  627.     public function getEmailLogsDir()
  628.     {
  629.         $home $this->getCustomLogsDir()."email_logs/";
  630.         return $home;
  631.     }
  632.     // Plan.io Task #4624
  633.     public function getProjectManagerLogsDir()
  634.     {
  635.         $home $this->getCustomLogsDir()."project_manager/";
  636.         return $home;
  637.     }
  638.     // Plan.io Task #4518
  639.     public function getNotifierLogsDir()
  640.     {
  641.         $home $this->getCustomLogsDir()."notifier/";
  642.         return $home;
  643.     }
  644.     public function getTemplateLogsDir()
  645.     {
  646.         $home $this->getCustomLogsDir()."template/";
  647.         return $home;
  648.     }
  649.     //--------------------------------------------------------------------------
  650.     // Plan.io Task #3922 
  651.     // DMS Global, Email and Object Logs
  652.     //--------------------------------------------------------------------------
  653.     // Old path : ROOT/custom_logs/global_logs
  654.     // New path : ROOT/DMS/Logs/Global/
  655.     public function getDMS_GlobalLogsDir()
  656.     {
  657.         $home dirname(__FILE__3);
  658.         $home .= "/DMS/Logs/Global/";
  659.         return $home;
  660.     }
  661.     
  662.     // DMS/Logs/Email/
  663.     public function getDMS_EmailLogsDir()
  664.     {        
  665.         $home dirname(__FILE__3);
  666.         $home .= "/DMS/Logs/Email/";
  667.         return $home;
  668.     }
  669.     // DMS/Logs/Mission/
  670.     public function getDMS_MissionLogsDir()
  671.     {        
  672.         $home dirname(__FILE__3);
  673.         $home .= "/DMS/Logs/Mission/";
  674.         return $home;
  675.     }
  676.     // DMS/Logs/Client/
  677.     public function getDMS_ClientLogsDir()
  678.     {        
  679.         $home dirname(__FILE__3);
  680.         $home .= "/DMS/Logs/Client/";
  681.         return $home;
  682.     }
  683.     // DMS/Logs/HumanResource/
  684.     public function getDMS_HumanResourceLogsDir()
  685.     {        
  686.         $home dirname(__FILE__3);
  687.         $home .= "/DMS/Logs/HumanResource/";
  688.         return $home;
  689.     }
  690.     // DMS/Logs/ProjectManager/Notebook/
  691.     public function getDMS_ProjectManagerNotebookLogsDir()
  692.     {        
  693.         $home dirname(__FILE__3);
  694.         $home .= "/DMS/Logs/ProjectManager/Notebook/";
  695.         return $home;
  696.     }
  697.     //--------------------------------------------------------------------------
  698.     public function getSecurityLogsDir()
  699.     {
  700.         $home $this->getCustomLogsDir()."security/";
  701.         return $home;
  702.     }
  703.     // Plan.io Task #4410
  704.     public function getWebappLogsDir()
  705.     {
  706.         $home $this->getCustomLogsDir()."webapp/";
  707.         return $home;
  708.     }
  709.     // Plan.io Task #4518
  710.     // Used in 
  711.     //    src/Services/Platform/NoteTools.php
  712.     //    src/Services/Communication/Email/NotifierEmails.php
  713.     //    src/Services/Ding/Notifier.php
  714.     public function notifier_debug($msg$active true)
  715.     {
  716.         if ($active)
  717.         {
  718.             $home $this->getNotifierLogsDir();
  719.             if (!is_dir($home))    $do mkdir($home0755true);
  720.     
  721.             $today = new \DateTime();
  722.             $log "notifier_debug_".$today->format("Y").$today->format("m").".log";
  723.             $logFile $home $log;
  724.     
  725.             $timestamp $today->format("[Y-m-d H:i:s] ");
  726.     
  727.             error_log("\n".$timestamp.$msg."\n",3,$logFile);
  728.             
  729.             error_log("\n".$timestamp.$msg."\n",3,"ploop.log");
  730.         }               
  731.     }
  732.     // Plan.io Task #4624
  733.     public function project_manager_debug($msg$active true)
  734.     {
  735.         if ($active)
  736.         {
  737.             $home $this->getProjectManagerLogsDir();
  738.             if (!is_dir($home))    $do mkdir($home0755true);
  739.             $today = new \DateTime();
  740.             $log "project_manager_debug_".$today->format("Y").$today->format("m").".log";
  741.             $logFile $home $log;
  742.             $timestamp $today->format("[Y-m-d H:i:s] ");
  743.             error_log("\n".$timestamp.$msg."\n",3,$logFile);            
  744.             
  745.             // error_log("\n".$timestamp.$msg."\n",3,"ploop.log");            
  746.         }        
  747.     }
  748.     // Plan.io Task #4483
  749.     public function analyzePlanning($isActive$msg)
  750.     {
  751.         if (!$isActive) return true;
  752.         $home $this->getPlanningLogsDir();
  753.         if (!is_dir($home))    $do mkdir($home0755true);
  754.         $today = new \DateTime();
  755.         $log "global_planning_execution_time_".$today->format("Y").$today->format("m").".log";
  756.         $logFile $home $log;
  757.         $timestamp $today->format("[Y-m-d H:i:s] ");
  758.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  759.     }
  760.     // Plan.io Task #4410
  761.     public function webapp_debug($msg)
  762.     {
  763.         $home $this->getWebappLogsDir();
  764.         if (!is_dir($home))    $do mkdir($home0755true);
  765.         $today = new \DateTime();
  766.         $log "webapp_debug_".$today->format("Y").$today->format("m").".log";
  767.         $logFile $home $log;
  768.         $timestamp $today->format("[Y-m-d H:i:s] ");
  769.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  770.     }
  771.     // Plan.io Task #4410
  772.     public function webapp_image_debug($msg)
  773.     {
  774.         $home $this->getWebappLogsDir();
  775.         if (!is_dir($home))    $do mkdir($home0755true);
  776.         $today = new \DateTime();
  777.         $log "webapp_image_debug_".$today->format("Y").$today->format("m").".log";
  778.         $logFile $home $log;
  779.         $timestamp $today->format("[Y-m-d H:i:s]");
  780.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  781.     }
  782.     public function getTakeOutExportDir()
  783.     {
  784.         $home $this->getCustomDataDir()."take_out_export/";
  785.         return $home;
  786.     }
  787.     public function getCssDir()
  788.     {
  789.         $home $this->getRootDir()."/public/theme/css/";
  790.         return $home;
  791.     }
  792.     public function getJohnDoeDir()
  793.     {
  794.         $home $this->getRootDir()."/public/assets/john_doe/";
  795.         return $home;
  796.     }
  797.     // custom_logs/cost/auto_accounting/
  798.     public function getCostAutoAccountingDebugDir()
  799.     {
  800.         $home $this->getCustomLogsDir()."cost/";
  801.         if (!is_dir($home))
  802.         {
  803.             $do mkdir($home0755true);
  804.             if ($do === false)
  805.             {
  806.                 $this->errorLog("Folder $home cannot be created.");
  807.                 return null;
  808.             }
  809.         }
  810.         $home .= 'auto_accounting/';
  811.         if (!is_dir($home))
  812.         {
  813.             $do mkdir($home0755true);
  814.             if ($do === false)
  815.             {
  816.                 $this->errorLog("Folder $home cannot be created.");
  817.                 return null;
  818.             }
  819.         }
  820.         return $home;
  821.     }
  822.     // custom_logs/invoice/auto_accounting/
  823.     public function getInvoiceAutoAccountingDebugDir()
  824.     {
  825.         $home $this->getCustomLogsDir()."invoice/";
  826.         if (!is_dir($home))
  827.         {
  828.             $do mkdir($home0755true);
  829.             if ($do === false)
  830.             {
  831.                 $this->errorLog("Folder $home cannot be created.");
  832.                 return null;
  833.             }
  834.         }
  835.         $home .= 'auto_accounting/';
  836.         if (!is_dir($home))
  837.         {
  838.             $do mkdir($home0755true);
  839.             if ($do === false)
  840.             {
  841.                 $this->errorLog("Folder $home cannot be created.");
  842.                 return null;
  843.             }
  844.         }
  845.         return $home;
  846.     }
  847.     // custom_logs/zone/{society_group_id}
  848.     public function getZoneDir($societyGroup null)
  849.     {
  850.         $home $this->getCustomLogsDir()."zone/";
  851.         if ($societyGroup !== null)
  852.         {
  853.             $id $societyGroup->getId();
  854.             $home .= $id."/";
  855.             if (!is_dir($home))
  856.             {
  857.                 $do mkdir($home0755true);
  858.                 if ($do === false)
  859.                 {
  860.                     $this->errorLog("Folder $home cannot be created.");
  861.                     return null;
  862.                 }
  863.             }
  864.         }
  865.         return $home;
  866.     }
  867.     // custom_logs/zone/debug/
  868.     public function getZoneDebugDir($societyGroup null)
  869.     {
  870.         $home $this->getZoneDir()."debug/";
  871.         return $home;
  872.     }
  873.     // custom_logs/availability/
  874.     public function getAvailablityDir()
  875.     {
  876.         $home $this->getCustomLogsDir()."availability/";
  877.         return $home;
  878.     }
  879.     // custom_logs/financial/
  880.     // Plan.io Task #4386
  881.     public function getFinancialDir()
  882.     {
  883.         $home $this->getCustomLogsDir()."financial/";
  884.         return $home;
  885.     }
  886.     // custom_logs/financial/scan_financial/
  887.     // Plan.io Task #4386
  888.     public function getScanFinancialDir()
  889.     {
  890.         $home $this->getFinancialDir()."scan_financial/";
  891.         return $home;
  892.     }
  893.     // custom_logs/financial/duplicate_code/
  894.     // Plan.io Task #4386
  895.     public function getDuplicateCodeFinancialDir()
  896.     {
  897.         $home $this->getFinancialDir()."duplicate_code/";
  898.         return $home;
  899.     }
  900.     // Plan.Io Task #3747
  901.     // custom_logs/individual/
  902.     public function getIndividualDir()
  903.     {
  904.         $home $this->getCustomLogsDir()."individual/";
  905.         if (!is_dir($home))
  906.         {
  907.             $do mkdir($home0755true);
  908.             if ($do === false)
  909.             {
  910.                 $this->errorLog("Folder $home cannot be created.");
  911.                 return null;
  912.             }
  913.         }
  914.         return $home;
  915.     }
  916.     // Plan.Io Task #3747
  917.     // custom_logs/individual/dump/{society_group_id}
  918.     public function getIndividualDumpDir($societyGroup null)
  919.     {
  920.         $home $this->getIndividualDir() . "dump/";
  921.         if ($societyGroup !== null)
  922.         {
  923.             $id $societyGroup->getId();
  924.             $home .= $id."/";
  925.             if (!is_dir($home))
  926.             {
  927.                 $do mkdir($home0755true);
  928.                 if ($do === false)
  929.                 {
  930.                     $this->errorLog("Folder $home cannot be created.");
  931.                     return null;
  932.                 }
  933.             }
  934.         }
  935.         return $home;
  936.     }
  937.     // Plan.io Task #3747
  938.     // custom_logs/individual/merge/{society_group_id}
  939.     public function getIndividualMergeDir($societyGroup null)
  940.     {
  941.         $home $this->getIndividualDir() . "merge/";
  942.         if ($societyGroup !== null)
  943.         {
  944.             $id $societyGroup->getId();
  945.             $home .= $id."/";
  946.             if (!is_dir($home))
  947.             {
  948.                 $do mkdir($home0755true);
  949.                 if ($do === false)
  950.                 {
  951.                     $this->errorLog("Folder $home cannot be created.");
  952.                     return null;
  953.                 }
  954.             }
  955.         }
  956.         return $home;
  957.     }
  958.     // Plan.io Task #4247
  959.     // custom_logs/mission/
  960.     public function getMissionDir()
  961.     {
  962.         $home $this->getCustomLogsDir()."mission/";
  963.         if (!is_dir($home))
  964.         {
  965.             $do mkdir($home0755true);
  966.             if ($do === false)
  967.             {
  968.                 $this->errorLog("Folder $home cannot be created.");
  969.                 return null;
  970.             }
  971.         }
  972.         return $home;
  973.     }
  974.     // Plan.io Task #4247
  975.     // custom_logs/mission/dump/{society_group_id}
  976.     public function getMissionDumpDir($societyGroup null)
  977.     {
  978.         $home $this->getMissionDir() . "dump/";
  979.         if ($societyGroup !== null)
  980.         {
  981.             $id $societyGroup->getId();
  982.             $home .= $id."/";
  983.             if (!is_dir($home))
  984.             {
  985.                 $do mkdir($home0755true);
  986.                 if ($do === false)
  987.                 {
  988.                     $this->errorLog("Folder $home cannot be created.");
  989.                     return null;
  990.                 }
  991.             }
  992.         }
  993.         return $home;
  994.     }
  995.     // Plan.io Task #4247
  996.     // custom_logs/mission/merge/{society_group_id}
  997.     public function getMissionMergeDir($societyGroup null)
  998.     {
  999.         $home $this->getMissionDir() . "merge/";
  1000.         if ($societyGroup !== null)
  1001.         {
  1002.             $id $societyGroup->getId();
  1003.             $home .= $id."/";
  1004.             if (!is_dir($home))
  1005.             {
  1006.                 $do mkdir($home0755true);
  1007.                 if ($do === false)
  1008.                 {
  1009.                     $this->errorLog("Folder $home cannot be created.");
  1010.                     return null;
  1011.                 }
  1012.             }
  1013.         }
  1014.         return $home;
  1015.     }
  1016.     // Plan.io Task #4331
  1017.     // custom_logs/payment_logs/YYYY/MM/
  1018.     public function getPaymentLogDir()
  1019.     {
  1020.         $home $this->getCustomLogsDir()."payment_logs/";
  1021.         return $home;
  1022.     }
  1023.     public function getPaymentErrorLogDir()
  1024.     {
  1025.         $home $this->getPaymentLogDir() . "error/";
  1026.         $now = new \DateTime();
  1027.         $home .= $now->format('Y') . "/" $now->format('m') . "/";
  1028.         return $home;
  1029.     }
  1030.     // Plan.io Task #4383
  1031.     public function getBookingLogDir()
  1032.     {
  1033.         $home $this->getCustomLogsDir()."booking/";
  1034.         return $home;
  1035.     }
  1036.     // Plan.io Task #4383
  1037.     public function getBookingSavSlotLogDir()
  1038.     {
  1039.         $home $this->getBookingLogDir()."booking_sav_slot/";
  1040.         return $home;
  1041.     }
  1042.     // Plan.io Task #4383
  1043.     public function getCleanBookingSavSlotLogDir()
  1044.     {
  1045.         $home $this->getBookingLogDir()."clean_booking_sav_slot/";
  1046.         return $home;
  1047.     }
  1048.     public function getGuardLogPath(SocietyGroup $societyGroup)
  1049.     {
  1050.         // Get the path to the log folder
  1051.         // If the folder does not exits, this creates it
  1052.         $logPath $this->getGuardLogsDir();
  1053.         // Try to get the name of the log file from the entity
  1054.         $logName $societyGroup->getGuardLog();
  1055.         // If empty, craft it
  1056.         if (empty($logName))
  1057.         {
  1058.             $today = new \DateTime();
  1059.             $logName "guard_log_".$today->format('Y_m_d')."_SG_".$societyGroup->getInternalRef().".log";
  1060.             // Update the object
  1061.             $societyGroup->setGuardLog($logName);
  1062.         }
  1063.         // Craft the path to the file
  1064.         $logFile $logPath $logName;
  1065.         // If the file does not exist, create it
  1066.         if (!file_exists($logFile))
  1067.         {
  1068.             error_log("",3,$logFile);
  1069.         }
  1070.         return $logFile;
  1071.     }
  1072.     public function addTimestampToGuardLog($logFile)
  1073.     {
  1074.         $today = new \DateTime();
  1075.         error_log("\n",3,$logFile);
  1076.         error_log("\n",3,$logFile);
  1077.         error_log($today->format("Y/m/d H:i:s"),3,$logFile);
  1078.         error_log("\n",3,$logFile);
  1079.     }
  1080.     public function mobileAppLogCall($message null)
  1081.     {
  1082.         // Global switch to enable/disable mobile app logging
  1083.         $mobileAppLoggingActive true;
  1084.         if(!$mobileAppLoggingActive)
  1085.             return false;
  1086.         // Returns User object or null if not authenticated
  1087.         $currentUser $this->getCurrentUser();
  1088.         if($currentUser === null// Do not permit log if user is not authenticated, should not happen
  1089.             return false;
  1090.         // Check that current user is not an AccessClient
  1091.         if(    ($currentUser instanceof AccessClient) )
  1092.             return false;
  1093.         $logPath $this->getApiIcodLogsDir();
  1094.         $now = new DateTime();
  1095.         $logPath $logPath 'api_rest_log/mobileAppCall_' $now->format('Y_m') . '.log';
  1096.         $today = new \DateTime();
  1097.         $currentDate $today->format('Y-m-d H:i:s.v');
  1098.         $trace debug_backtrace();
  1099.         $func $trace[1]["function"];
  1100.         $line "" $currentDate "," $currentUser->display() . "," $currentUser->getId() . "," $currentUser->getSocietyGroup()?->getRef() . "," $currentUser->getSocietyGroup()?->getId() . "," $func;
  1101.         if($message !== null)
  1102.             $line .= "," $message;
  1103.         $line .= "\n";
  1104.         error_log($line3$logPath);
  1105.     }
  1106.     public function getApiRestRateLimitLogPath(): string
  1107.     {
  1108.         $baseDir $this->getApiIcodLogsDir() . "api_rest_log/";
  1109.         if (!is_dir($baseDir))
  1110.         {
  1111.             if (!mkdir($baseDir0755true))
  1112.             {
  1113.                 $now = new \DateTime();
  1114.                 return $baseDir "rate_limit_" $now->format("Y") . "_" $now->format("m") . ".csv";
  1115.             }
  1116.         }
  1117.         $now = new \DateTime();
  1118.         $fileName "rate_limit_" $now->format("Y") . "_" $now->format("m") . ".csv";
  1119.         return $baseDir $fileName;
  1120.     }
  1121.     public function apiRestRateLimitLog(array $args): void
  1122.     {
  1123.         $scope array_key_exists('scope'$args) ? (string) $args['scope'] : '';
  1124.         $ip array_key_exists('ip'$args) ? (string) $args['ip'] : '';
  1125.         $accessApi array_key_exists('accessApi'$args) && $args['accessApi'] instanceof AccessAPI $args['accessApi'] : null;
  1126.         $route array_key_exists('route'$args) ? (string) $args['route'] : '';
  1127.         $maxRequests array_key_exists('max_requests'$args) ? $args['max_requests'] : '';
  1128.         $accessApiId '';
  1129.         $accessApiUsername '';
  1130.         $societyGroupId '';
  1131.         $societyGroupRef '';
  1132.         if ($accessApi instanceof AccessAPI)
  1133.         {
  1134.             $accessApiId = (string) $accessApi->getId();
  1135.             $accessApiUsername = (string) $accessApi->getUsername();
  1136.             $societyGroup $accessApi->getSocietyGroup();
  1137.             if ($societyGroup instanceof SocietyGroup)
  1138.             {
  1139.                 $societyGroupId = (string) $societyGroup->getId();
  1140.                 $societyGroupRef = (string) $societyGroup->getRef();
  1141.             }
  1142.         }
  1143.         $path $this->getApiRestRateLimitLogPath();
  1144.         $fileExists file_exists($path);
  1145.         $stream fopen($path$fileExists "a" "w");
  1146.         if ($stream === false)
  1147.         {
  1148.             return;
  1149.         }
  1150.         if (!$fileExists)
  1151.         {
  1152.             $header = [
  1153.                 "timestamp",
  1154.                 "scope",
  1155.                 "ip",
  1156.                 "access_api.id",
  1157.                 "access_api.username",
  1158.                 "society_group.id",
  1159.                 "society_group.ref",
  1160.                 "route",
  1161.                 "max_requests",
  1162.             ];
  1163.             fputcsv($stream$header';');
  1164.         }
  1165.         $now = new \DateTime();
  1166.         $timestamp $now->format("Y-m-d H:i:s");
  1167.         $line = [
  1168.             $timestamp,
  1169.             $scope,
  1170.             $ip,
  1171.             $accessApiId,
  1172.             $accessApiUsername,
  1173.             $societyGroupId,
  1174.             $societyGroupRef,
  1175.             $route,
  1176.             $maxRequests,
  1177.         ];
  1178.         fputcsv($stream$line';');
  1179.         fclose($stream);
  1180.     }
  1181.     public function mobileAppLog(array $args)
  1182.     {
  1183.         if (empty($args['info_error'])) return false;
  1184.         // Get data
  1185.         $errorCode $args['info_error']['errorCode'];
  1186.         $errorMessage $args['info_error']['errorMessage'];
  1187.         $message array_key_exists('message'$args) ? $args['message'] : null;
  1188.         // Optional
  1189.         $author array_key_exists('author'$args) ? $args['author'] : null;
  1190.         if ($author === null)
  1191.         {
  1192.             if ($this->security->getUser() instanceof Access)
  1193.             {
  1194.                 $author $this->security->getUser();
  1195.             }
  1196.             else
  1197.             {
  1198.                 $author $this->em
  1199.                     ->getRepository(Access::class)
  1200.                     ->findOneByUsername(Access::API_ACCESS);
  1201.             }
  1202.         }
  1203.         $authorId '';
  1204.         $authorUsername '';
  1205.         $authorSocietyGroup '';
  1206.         $authorSocietyGroupId '';
  1207.         if ($author !== null)
  1208.         {
  1209.             $authorId $author->getId();
  1210.             $authorUsername $author->getUsername();
  1211.             $authorSocietyGroup $author->getSocietyGroup();
  1212.             if ($authorSocietyGroup !== null) {
  1213.                 $authorSocietyGroupId $authorSocietyGroup->getId();
  1214.             }
  1215.         }
  1216.         // Handle OriginalUser
  1217.         $originalUser $this->getOriginalUser();
  1218.         $originalUserId '';
  1219.         $originalUserName '';
  1220.         if ($originalUser !== null)
  1221.         {
  1222.             $originalUserId $originalUser->getId();
  1223.             $originalUserName $originalUser->getUserIdentifier();
  1224.         }
  1225.         // Error
  1226.         $error false;
  1227.         if (array_key_exists('error'$args) && ($args['error'] == false || $args['error'] == true))
  1228.         {
  1229.             $error $args['error'];
  1230.         }
  1231.         $status $error 'ERROR' 'DONE';
  1232.         $logPath $this->getApiIcodLogsDir();
  1233.         $now = new DateTime();
  1234.         $logPath $logPath 'api_rest_log/mobile_app_' $now->format('Y_m') . '.log';
  1235.         $path $logPath;
  1236.         // Backtrace
  1237.         $backTrace debug_backtrace()[1];
  1238.         $backTraceMethod $backTrace['function'];
  1239.         $backTraceClass $backTrace['class'];
  1240.         // Date
  1241.         $now = new \DateTime();
  1242.         $nowDate $now->format('Y-m-d H:i:s');
  1243.         $line "[ " $nowDate " ][ " $status " ][ " $errorCode " ][ " $errorMessage " ][ id societyGroup : " $authorSocietyGroupId " ][ id access : " $authorId " ][ " $authorUsername " ][ " $originalUserId " ][ " $originalUserName " ][ " $backTraceClass " ][ " $backTraceMethod " ]\t";
  1244.         if(!empty($message)) $line .= " : " $message;
  1245.         $line .= "\n";
  1246.         error_log($line3$logPath);
  1247.     }
  1248.     public function mobileAppLogInternal(array $args)
  1249.     {
  1250.         if (empty($args)) return false;
  1251.         if (!array_key_exists('info_error'$args) || !is_array($args['info_error']))
  1252.         {
  1253.             return false;
  1254.         }
  1255.         $infoError $args['info_error'];
  1256.         $author array_key_exists('author'$args) ? $args['author'] : null;
  1257.         if ($author === null)
  1258.         {
  1259.             if ($this->security->getUser() instanceof Access)
  1260.             {
  1261.                 $author $this->security->getUser();
  1262.             }
  1263.             else
  1264.             {
  1265.                 $author $this->em
  1266.                     ->getRepository(Access::class)
  1267.                     ->findOneByUsername(Access::API_ACCESS);
  1268.             }
  1269.         }
  1270.         $authorId '';
  1271.         $authorUsername '';
  1272.         $authorSocietyGroupId '';
  1273.         if ($author !== null)
  1274.         {
  1275.             $authorId $author->getId();
  1276.             $authorUsername $author->getUsername();
  1277.             $authorSocietyGroup $author->getSocietyGroup();
  1278.             if ($authorSocietyGroup !== null)
  1279.             {
  1280.                 $authorSocietyGroupId $authorSocietyGroup->getId();
  1281.             }
  1282.         }
  1283.         $originalUser $this->getOriginalUser();
  1284.         $originalUserId '';
  1285.         $originalUserName '';
  1286.         if ($originalUser !== null)
  1287.         {
  1288.             $originalUserId $originalUser->getId();
  1289.             $originalUserName $originalUser->getUserIdentifier();
  1290.         }
  1291.         $now = new DateTime();
  1292.         $logPath $this->getApiIcodLogsDir();
  1293.         $logPath $logPath 'api_rest_log/mobile_app_internal_' $now->format('Y_m') . '.log';
  1294.         if (!file_exists($logPath))
  1295.         {
  1296.             $header "[ Date ][ Code ][ Message ][ GUID ][ GUID Entity ][ Date Error ][ OS ][ Version ][ id societyGroup ][ id access ][ Author ][ OriginalUserId ][ OriginalUserName ][ StackTrace ]";
  1297.             error_log($header "\n"3$logPath);
  1298.         }
  1299.         $stackTrace array_key_exists('stackTrace'$infoError) ? $infoError['stackTrace'] : null;
  1300.         $code array_key_exists('code'$infoError) ? $infoError['code'] : null;
  1301.         $message array_key_exists('message'$infoError) ? $infoError['message'] : null;
  1302.         $guid array_key_exists('guid'$infoError) ? $infoError['guid'] : null;
  1303.         $guidEntity array_key_exists('guidEntity'$infoError) ? $infoError['guidEntity'] : null;
  1304.         $date array_key_exists('date'$infoError) ? $infoError['date'] : null;
  1305.         $version array_key_exists('version'$infoError) ? $infoError['version'] : null;
  1306.         $os array_key_exists('os'$infoError) ? $infoError['os'] : null;
  1307.         $info array_key_exists('info'$infoError) ? $infoError['info'] : null;
  1308.         $nowDate $now->format('Y-m-d H:i:s');
  1309.         $line "[ " $nowDate " ][ " $code " ][ " $message " ][ " $guid " ][ " $guidEntity " ][ " $date " ][ " $os " ][ " $version " ][ id societyGroup : " $authorSocietyGroupId " ][ id access : " $authorId " ][ " $authorUsername " ][ " $originalUserId " ][ " $originalUserName " ][ " $stackTrace " ]";
  1310.         if (!empty($info)) $line .= " : " $info;
  1311.         $line .= "\n";
  1312.         error_log($line3$logPath);
  1313.     }
  1314.     public function hasMobileAppLogGuid($guid): bool
  1315.     {
  1316.         if ($guid === null || empty($guid))
  1317.         {
  1318.             return false;
  1319.         }
  1320.         $baseDir $this->getApiIcodLogsDir() . 'api_rest_log/';
  1321.         if (!is_dir($baseDir))
  1322.         {
  1323.             return false;
  1324.         }
  1325.         $pattern $baseDir 'mobile_app_internal_*.log';
  1326.         $needle '[ ' $guid ' ]';
  1327.         $files glob($pattern);
  1328.         if ($files === false)
  1329.         {
  1330.             return false;
  1331.         }
  1332.         foreach ($files as $file)
  1333.         {
  1334.             $handle = @fopen($file'rb');
  1335.             if ($handle === false)
  1336.             {
  1337.                 continue;
  1338.             }
  1339.             while (($line fgets($handle)) !== false)
  1340.             {
  1341.                 if (strpos($line$needle) !== false)
  1342.                 {
  1343.                     fclose($handle);
  1344.                     return true;
  1345.                 }
  1346.             }
  1347.             fclose($handle);
  1348.         }
  1349.         return false;
  1350.     }
  1351.     public function planning_optimisation_error_log($args)
  1352.     {
  1353.         $home $this->getPlanningOptimisationLogsDir();
  1354.         if (!is_dir($home))    $do mkdir($home0755true);
  1355.         $home .= "errors/";
  1356.         if (!is_dir($home))    $do mkdir($home0755true);
  1357.         $today = new \DateTime();
  1358.         $log "planning_errors_".$today->format("Ymd").".log";
  1359.         $logFile $home $log;
  1360.         $jsonString json_encode($argsJSON_PRETTY_PRINT);
  1361.         $fp fopen($logFile'a');
  1362.         // Is it empty ?
  1363.         if (filesize($logFile))
  1364.         {
  1365.             // Not empty
  1366.             // Remove last char "}" of file and add ,
  1367.             $stat fstat($fp);
  1368.             ftruncate($fp$stat['size']-1);
  1369.             fwrite($fp",\n");
  1370.         }
  1371.         else
  1372.         {
  1373.             // Empty
  1374.             // Write begining of json object
  1375.             fwrite($fp"{\n");
  1376.         }
  1377.         fwrite($fp'"'.uniqid().'"' " : ");
  1378.         fwrite($fp$jsonString);
  1379.         fwrite($fp"}");
  1380.         fclose($fp);
  1381.     }
  1382.     public function kitchenPlannerErrorlog($msg)
  1383.     {
  1384.         $home $this->getIkeaKitchenPlannerLogsDir();
  1385.         if (!is_dir($home))    
  1386.             mkdir($home0755true);
  1387.         $home .= "errors/";
  1388.         if (!is_dir($home))
  1389.             mkdir($home0755true);
  1390.         $today = new \DateTime();
  1391.         $log "kitchen_planner_errors_".$today->format("Ymd").".log";
  1392.         $logFile $home $log;
  1393.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1394.         $backTrace debug_backtrace()[1];
  1395.         $method $backTrace['function'];
  1396.         $class $backTrace['class'];
  1397.         $trace $class."::".$method;
  1398.         $trace str_replace("\\""::"$trace);
  1399.         $content "[".$trace "] " $msg;
  1400.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1401.     }
  1402.     public function planning_optimisation_debug($active$msg)
  1403.     {
  1404.         if (!$active)
  1405.             return false;
  1406.         $home $this->getPlanningOptimisationLogsDir();
  1407.         if (!is_dir($home))    $do mkdir($home0755true);
  1408.         $today = new \DateTime();
  1409.         $ym $today->format('Y_m');
  1410.         $log "planning_optimisation_debug_$ym.log";
  1411.         $logFile $home $log;
  1412.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1413.         $backTrace debug_backtrace()[1];
  1414.         $method $backTrace['function'];
  1415.         $class $backTrace['class'];
  1416.         $trace $class."::".$method;
  1417.         $trace str_replace("\\""::"$trace);
  1418.         $content "[".$trace "] " $msg;
  1419.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1420.     }
  1421.     // Logs Errors to root/custom_logs/stripe/errors/stripe_errors_yyyymmdd.log
  1422.     // One single log each day
  1423.     public function stripe_error_log($args)
  1424.     {
  1425.         $home $this->getStripeLogsDir();
  1426.         if (!is_dir($home))    $do mkdir($home0755true);
  1427.         $home .= "errors/";
  1428.         if (!is_dir($home))    $do mkdir($home0755true);
  1429.         $today = new \DateTime();
  1430.         $log "stripe_errors_".$today->format("Ymd").".log";
  1431.         $logFile $home $log;
  1432.         $jsonString json_encode($argsJSON_PRETTY_PRINT);
  1433.         $fp fopen($logFile'a');
  1434.         // Is it empty ?
  1435.         if (filesize($logFile))
  1436.         {
  1437.             // Not empty
  1438.             // Remove last char "}" of file and add ,
  1439.             $stat fstat($fp);
  1440.             ftruncate($fp$stat['size']-1);
  1441.             fwrite($fp",\n");
  1442.         }
  1443.         else
  1444.         {
  1445.             // Empty
  1446.             // Write begining of json object
  1447.             fwrite($fp"{\n");
  1448.         }
  1449.         fwrite($fp'"'.uniqid().'"' " : ");
  1450.         fwrite($fp$jsonString);
  1451.         fwrite($fp"}");
  1452.         fclose($fp);
  1453.     }
  1454.     // Logs Errors to root/custom_logs/guest_suite_log/guest_suite_yyyymmdd.log
  1455.     // One single log each day
  1456.     public function guest_suite_log($args)
  1457.     {
  1458.         $home $this->getGuestSuiteLogsDir();
  1459.         if (!is_dir($home))    $do mkdir($home0755true);
  1460.         $today = new \DateTime();
  1461.         $log "guest_suite_".$today->format("Ymd").".log";
  1462.         $logFile $home $log;
  1463.         $jsonString json_encode($argsJSON_PRETTY_PRINT);
  1464.         $fp fopen($logFile'a');
  1465.         // Is it empty ?
  1466.         if (filesize($logFile))
  1467.         {
  1468.             // Not empty
  1469.             // Remove last char "}" of file and add ,
  1470.             $stat fstat($fp);
  1471.             ftruncate($fp$stat['size']-1);
  1472.             fwrite($fp",\n");
  1473.         }
  1474.         else
  1475.         {
  1476.             // Empty
  1477.             // Write begining of json object
  1478.             fwrite($fp"{\n");
  1479.         }
  1480.         fwrite($fp'"'.uniqid().'"' " : ");
  1481.         fwrite($fp$jsonString);
  1482.         fwrite($fp"}");
  1483.         fclose($fp);
  1484.     }
  1485.     // Logs to root/custom_logs/sms_logs/sms_reminder_task_yyyy_mm.log
  1486.     // Used by CRON command reminder
  1487.     public function sms_reminder_debug($active$msg)
  1488.     {
  1489.         if (!$active)
  1490.             return false;
  1491.         $home $this->getSmsLogsDir();
  1492.         if (!is_dir($home))    $do mkdir($home0755true);
  1493.         $today = new \DateTime();
  1494.         $ym $today->format('Y_m');
  1495.         $log "sms_reminder_task_$ym.log";
  1496.         $logFile $home $log;
  1497.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1498.         $content $timestamp $msg;
  1499.         error_log("\n".$content,3,$logFile);
  1500.     }
  1501.     // Logs to root/custom_logs/sms_logs/sms_debug_yyyy_mm.log
  1502.     // Used to debug info SMS
  1503.     // For errors check LogTools::smsLogDebug method/file
  1504.     public function sms_debug($active$msg)
  1505.     {
  1506.         if (!$active)
  1507.             return false;
  1508.         $home $this->getSmsLogsDir();
  1509.         if (!is_dir($home))    $do mkdir($home0755true);
  1510.         $today = new \DateTime();
  1511.         $ym $today->format('Y_m');
  1512.         $log "sms_debug_$ym.log";
  1513.         $logFile $home $log;
  1514.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1515.         $backTrace debug_backtrace()[1];
  1516.         $method $backTrace['function'];
  1517.         $class $backTrace['class'];
  1518.         $trace $class."::".$method;
  1519.         $trace str_replace("\\""::"$trace);
  1520.         $content "[".$trace "] " $msg;
  1521.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1522.     }
  1523.     // Logs to root/custom_logs/email_logs/email_debug_yyyy_mm.log
  1524.     // Handles Backtrace info
  1525.     public function email_debug($active$msg)
  1526.     {
  1527.         if (!$active)
  1528.             return false;
  1529.         $home $this->getEmailLogsDir();
  1530.         if (!is_dir($home))    $do mkdir($home0755true);
  1531.         $today = new \DateTime();
  1532.         $ym $today->format('Y_m');
  1533.         $log "email_debug_$ym.log";
  1534.         $logFile $home $log;
  1535.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1536.         $backTrace debug_backtrace()[1];
  1537.         $method $backTrace['function'];
  1538.         $class $backTrace['class'];
  1539.         $trace $class."::".$method;
  1540.         $trace str_replace("\\""::"$trace);
  1541.         $content "[".$trace "] " $msg;
  1542.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1543.     }
  1544.     // Logs to root/custom_logs/stripe/stripe_yyyymmdd.log
  1545.     // One single log each day
  1546.     public function stripe_debug($active$msg)
  1547.     {
  1548.         if (!$active)
  1549.             return false;
  1550.         $home $this->getStripeLogsDir();
  1551.         if (!is_dir($home))    $do mkdir($home0755true);
  1552.         $today = new \DateTime();
  1553.         $log "stripe_".$today->format("Ymd").".log";
  1554.         $logFile $home $log;
  1555.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1556.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  1557.     }
  1558.     // OLD : Logs to root/custom_logs/ikea_debug/ikea_os_yyyymm.log
  1559.     // NEW : Logs to root/custom_logs/ikea_debug/ikea_os_yyyy_week_{weekNumber}.log
  1560.     // One single log each week - Log file created on Monday
  1561.     public function ikea_debug($active$msg)
  1562.     {
  1563.         if (!$active)
  1564.             return false;
  1565.         $home $this->getCustomLogsDir()."ikea_debug/";
  1566.         if (!is_dir($home))    $do mkdir($home0755true);
  1567.         $today = new \DateTime();
  1568.         
  1569.         // Old format : Each month
  1570.         // $log = "ikea_os_".$today->format("Y").$today->format("m").".log";
  1571.         // New format : Each week on Mondays
  1572.         // ikea_os_2026_week_21.log
  1573.         $log "ikea_os_".$today->format("o")."_week_".$today->format("W").".log";
  1574.         $logFile $home $log;
  1575.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1576.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  1577.         
  1578.         $this->plooplog("\n".$timestamp.$msg."\n");
  1579.     }
  1580.     // Logs to root/custom_logs/ikea_debug_status/ikea_os_status_yyyymmdd.log
  1581.     // One single log each day
  1582.     public function ikea_debug_status($active$msg)
  1583.     {
  1584.         if (!$active)
  1585.             return false;
  1586.         $home $this->getCustomLogsDir()."ikea_debug_status/";
  1587.         if (!is_dir($home))    $do mkdir($home0755true);
  1588.         $today = new \DateTime();
  1589.         $log "ikea_os_status_".$today->format("Ymd").".log";
  1590.         $logFile $home $log;
  1591.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1592.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  1593.     }
  1594.     // Logs to root/custom_logs/ikea_debug_status/ikea_os_cancelled_yyyymm.log
  1595.     // One single log each month
  1596.     public function ikea_debug_cancelled($active$msg)
  1597.     {
  1598.         if (!$active)
  1599.             return false;
  1600.         $home $this->getCustomLogsDir()."ikea_debug_status/";
  1601.         if (!is_dir($home))    $do mkdir($home0755true);
  1602.         $today = new \DateTime();
  1603.         $log "ikea_os_cancelled_".$today->format("Ym").".log";
  1604.         $logFile $home $log;
  1605.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1606.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  1607.     }
  1608.     public function ikea_send($args)
  1609.     {
  1610.         //Returns User object or null if not authenticated
  1611.         $currentUser $this->getCurrentUser();
  1612.         if ($currentUser === null)
  1613.         {
  1614.             return false;
  1615.         }
  1616.         $home $this->getIkeaSendLogsDir($currentUser->getSocietyGroup());
  1617.         if ($home === null)
  1618.         {
  1619.             return false;
  1620.         }
  1621.         $now = new \DateTime();
  1622.         $log "ikea_object_send_".$now->format("Ym").".csv";
  1623.         $logFile $home $log;
  1624.         // $user = array_key_exists('user', $args) ? (string) $args['user'] : '';
  1625.         $filename array_key_exists('filename'$args) ? (string) $args['filename'] : '';
  1626.         $targetPath array_key_exists('targetPath'$args) ? (string) $args['targetPath'] : '';
  1627.         $ikeaOrderNumber array_key_exists('ikeaOrderNumber'$args) ? (string) $args['ikeaOrderNumber'] : '';
  1628.         $action array_key_exists('action'$args) ? (string) $args['action'] : '';
  1629.         $result array_key_exists('result'$args) ? (string) $args['result'] : '';
  1630.         $fileExists file_exists($logFile);
  1631.         $stream fopen($logFile$fileExists "a" "w");
  1632.         if ($stream === false)
  1633.         {
  1634.             return false;
  1635.         }
  1636.         if (!$fileExists)
  1637.         {
  1638.             $header = [
  1639.                 "timestamp",
  1640.                 "user",
  1641.                 "filename",
  1642.                 "targetPath",
  1643.                 "ikeaOrderNumber",
  1644.                 "action",
  1645.                 "result",
  1646.             ];
  1647.             fputcsv($stream$header';');
  1648.         }
  1649.         $timestamp $now->format("Y-m-d H:i:s");
  1650.         $line = [
  1651.             $timestamp,
  1652.             $currentUser->getUsername(),
  1653.             $filename,
  1654.             $targetPath,
  1655.             $ikeaOrderNumber,
  1656.             $action,
  1657.             $result,
  1658.         ];
  1659.         fputcsv($stream$line';');
  1660.         fclose($stream);
  1661.         return true;
  1662.     }
  1663.     
  1664.     // Logs to root/custom_logs/cost/auto_accounting/cost_auto_accounting_debug_yyyy_mm_dd.log
  1665.     // Handles Backtrace info
  1666.     public function cost_auto_accounting_debug($active$msg)
  1667.     {
  1668.         if (!$active)
  1669.             return false;
  1670.         $home $this->getCostAutoAccountingDebugDir();
  1671.         if ($home === null) return false;
  1672.         $today = new \DateTime();
  1673.         $ym $today->format('Y_m_d');
  1674.         $log "cost_auto_accounting_debug_$ym.log";
  1675.         $logFile $home $log;
  1676.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1677.         $backTrace debug_backtrace()[1];
  1678.         $method $backTrace['function'];
  1679.         $class $backTrace['class'];
  1680.         $trace $class."::".$method;
  1681.         $trace str_replace("\\""::"$trace);
  1682.         $content "[".$trace "] " $msg;
  1683.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1684.         return true;
  1685.     }
  1686.     
  1687.     // Logs to root/custom_logs/invoice/auto_accounting/invoice_auto_accounting_debug_yyyy_mm_dd.log
  1688.     // Handles Backtrace info
  1689.     public function invoice_auto_accounting_debug($active$msg)
  1690.     {
  1691.         if (!$active)
  1692.             return false;
  1693.         $home $this->getInvoiceAutoAccountingDebugDir();
  1694.         if ($home === null) return false;
  1695.         $today = new \DateTime();
  1696.         $ym $today->format('Y_m_d');
  1697.         $log "invoice_auto_accounting_debug_$ym.log";
  1698.         $logFile $home $log;
  1699.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1700.         $backTrace debug_backtrace()[1];
  1701.         $method $backTrace['function'];
  1702.         $class $backTrace['class'];
  1703.         $trace $class."::".$method;
  1704.         $trace str_replace("\\""::"$trace);
  1705.         $content "[".$trace "] " $msg;
  1706.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1707.         return true;
  1708.     }
  1709.     // Logs to root/custom_logs/zone/debug/zone_debug_yyyy_mm_dd.log
  1710.     // Handles Backtrace info
  1711.     public function zone_debug($active$msg)
  1712.     {
  1713.         if (!$active)
  1714.             return false;
  1715.         $home $this->getZoneDebugDir();
  1716.         if (!is_dir($home))    $do mkdir($home0755true);
  1717.         $today = new \DateTime();
  1718.         $ym $today->format('Y_m_d');
  1719.         $log "zone_debug_$ym.log";
  1720.         $logFile $home $log;
  1721.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1722.         $backTrace debug_backtrace()[1];
  1723.         $method $backTrace['function'];
  1724.         $class $backTrace['class'];
  1725.         $trace $class."::".$method;
  1726.         $trace str_replace("\\""::"$trace);
  1727.         $content "[".$trace "] " $msg;
  1728.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1729.     }
  1730.     // Logs to root/custom_logs/itask_logs/debug/debug_yyyy_mm_dd.log
  1731.     public function itask_debug($active$msg)
  1732.     {
  1733.         if (!$active)
  1734.             return false;
  1735.         $home $this->getITaskDebugDir();
  1736.         if (!is_dir($home))    $do mkdir($home0755true);
  1737.         $today = new \DateTime();
  1738.         $ym $today->format('Y_m_d');
  1739.         $log "debug_$ym.log";
  1740.         $logFile $home $log;
  1741.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1742.         $content $msg;
  1743.         // $backTrace = debug_backtrace()[1];
  1744.         // $method = $backTrace['function'];
  1745.         // $class = $backTrace['class'];
  1746.         // $trace = $class."::".$method;
  1747.         // $trace = str_replace("\\", "::", $trace);
  1748.         //
  1749.         // $content = "[".$trace . "] " . $msg;
  1750.         error_log("\n".$timestamp.$content."\n",3,$logFile);
  1751.     }
  1752.     // Logs to root/custom_logs/pra/pra_os_yyyymm.log
  1753.     // One single log each month
  1754.     public function pra_debug($active$msg)
  1755.     {
  1756.         if (!$active)
  1757.             return false;
  1758.         $home $this->getCustomLogsDir()."pra/";
  1759.         if (!is_dir($home))    $do mkdir($home0755true);
  1760.         $today = new \DateTime();
  1761.         $log "pra_".$today->format("Y").$today->format("m").".log";
  1762.         $logFile $home $log;
  1763.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1764.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  1765.     }
  1766.     // Used to trace SMS related errors
  1767.     // For happy path check LogTools::sms_debug method/file
  1768.     public function smsLogDebug($msg$activeProvider null)
  1769.     {
  1770.         $today = new \DateTime();
  1771.         $ym $today->format('Y_m');
  1772.         $backTrace debug_backtrace()[1];
  1773.         $method $backTrace['function'];
  1774.         $class $backTrace['class'];
  1775.         $trace $class."::".$method;
  1776.         $traceLevelOne str_replace("\\""::"$trace);
  1777.         $backTrace debug_backtrace()[2];
  1778.         $method $backTrace['function'];
  1779.         $class $backTrace['class'];
  1780.         $trace $class."::".$method;
  1781.         $traceLevelTwo str_replace("\\""::"$trace);
  1782.         // $backTrace = debug_backtrace()[3];
  1783.         // $method = $backTrace['function'];
  1784.         // $class = $backTrace['class'];
  1785.         // $trace = $class."::".$method;
  1786.         // $traceLevelThree = str_replace("\\", "::", $trace);
  1787.         // $content = $traceLevelOne . " : " . $traceLevelTwo . " : " . $traceLevelThree . " : " . $msg;
  1788.         $content $traceLevelOne " : " $traceLevelTwo " : " $msg;
  1789.         if ($activeProvider !== null)
  1790.         {
  1791.             if ($activeProvider->isSmsMode())
  1792.             {
  1793.                 $file $this->getSmsLogsDir() . "sms_mode_$ym.log";
  1794.             }
  1795.             else
  1796.             {
  1797.                 if ($activeProvider->isSmsTwilio())
  1798.                 {
  1799.                     $file $this->getSmsLogsDir() . "sms_twilio_$ym.log";
  1800.                 }
  1801.             }
  1802.         }
  1803.         else
  1804.         {
  1805.             $file $this->getSmsLogsDir() . "sms_unknown_provider_$ym.log";
  1806.         }
  1807.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1808.         error_log("\n".$timestamp.$content."\n",3,$file);
  1809.     }
  1810.     // Task plan.io #4024
  1811.     // Logs to root/custom_logs/availability/availability_clean_{Y_m_d}.log
  1812.     public function availabilityClean_log($msg)
  1813.     {
  1814.         $home $this->getAvailablityDir();
  1815.         if (!is_dir($home))    $do mkdir($home0755true);
  1816.         $today = new \DateTime();
  1817.         $log "availability_clean_" $today->format("Y") . "_" $today->format("m") . "_" $today->format("d") . ".log";
  1818.         $logFile $home $log;
  1819.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1820.         error_log("\n".$timestamp.$msg."\n",3,$logFile);
  1821.     }
  1822.     // Task plan.io #4386
  1823.     // Logs to root/custom_logs/financial/scan_financial/scan_financial_{Y_m_d}.log
  1824.     public function scanFinancialCommand_log($msg)
  1825.     {
  1826.         $home $this->getScanFinancialDir();
  1827.         if (!is_dir($home))    $do mkdir($home0755true);
  1828.         $today = new \DateTime();
  1829.         $log "scan_financial_" $today->format("Y_m_d") . ".log";
  1830.         $logFile $home $log;
  1831.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1832.         error_log($timestamp.$msg."\n",3,$logFile);
  1833.     }
  1834.     // Task plan.io #4386
  1835.     // Logs to root/custom_logs/financial/duplicate_code/duplicate_code_{Y_m_d}.log
  1836.     public function logDuplicateFinancialCode(Client $client, array $clientsSameAccount)
  1837.     {
  1838.         $home $this->getDuplicateCodeFinancialDir();
  1839.         if (!is_dir($home))    $do mkdir($home0755true);
  1840.         $today = new \DateTime();
  1841.         $log "duplicate_code_" $today->format("Y_m_d") . ".log";
  1842.         $logFile $home $log;
  1843.         // Build log message
  1844.         $societyGroup $client->getSocietyGroup();
  1845.         $financial $client->getFinancial();
  1846.         $societyGroupDisplay $societyGroup !== null $societyGroup->displayForLog() : '';
  1847.         $financialDisplay $financial !== null $financial->displayForLog() : '';
  1848.         $timestamp $today->format("[Y-m-d H:i:s] ");
  1849.         $msg "-------------------";
  1850.         $msg .= "\n" $timestamp;
  1851.         $msg .= "\nSocietyGroup : " $societyGroupDisplay;
  1852.         $msg .= "\nClient : " $client->displayForLog();
  1853.         $msg .= "\nIndividual : " $client->displayChildrenForLog();
  1854.         $msg .= "\nFinancial : " $financialDisplay;
  1855.         $msg .= "\n";
  1856.         $msg .= "\nOther client/financial concerned\n";
  1857.         foreach($clientsSameAccount as $clientSameAccount)
  1858.         {
  1859.             $financialSameAccount $clientSameAccount->getFinancial();
  1860.             if ($financialSameAccount === null) continue;
  1861.             $msg .= "\nClient : " $clientSameAccount->displayForLog();
  1862.             $msg .= ", Individual : " $clientSameAccount->displayChildrenForLog();
  1863.             $msg .= ", Financial : " $financialSameAccount->displayForLog();
  1864.         }
  1865.         error_log("\n" $msg,3,$logFile);
  1866.     }
  1867.     // Task plan.io #4331
  1868.     // Logs to root/custom_logs/payment_logs/error
  1869.     public function payment_log_error($msg$args)
  1870.     {
  1871.         // Setup
  1872.         $today = new \DateTime();
  1873.         $backTrace debug_backtrace()[1];
  1874.         $method $backTrace['function'];
  1875.         $class $backTrace['class'];
  1876.         $trace $class."::".$method;
  1877.         // Build logFile
  1878.         $home $this->getPaymentErrorLogDir();
  1879.         if (!is_dir($home))    mkdir($home0755true);
  1880.         // Build args
  1881.         $societyGroupDisplay "no_society_group";
  1882.         if (array_key_exists('society_group'$args) && $args['society_group'] instanceof SocietyGroup)
  1883.         {
  1884.             $societyGroupDisplay $args['society_group']->displayForLog();
  1885.         }
  1886.         $type = !empty($args['type']) ? $args['type'] : "";
  1887.         switch($type)
  1888.         {
  1889.             case OnlinePaymentType::CODE_STRIPE:
  1890.             {
  1891.                 $prefixLog "STRIPE";
  1892.                 break;
  1893.             }
  1894.             case OnlinePaymentType::CODE_PAYPAL:
  1895.             {
  1896.                 $prefixLog "PAYPAL";
  1897.                 break;
  1898.             }
  1899.             default:
  1900.             {
  1901.                 $prefixLog "PAYMENT";
  1902.                 break;
  1903.             }
  1904.         }
  1905.         $logFilename "payment_error_" $today->format("Y-m-d") . ".log";
  1906.         $logFilename $home $logFilename;
  1907.         if (!file_exists($logFilename))
  1908.         {
  1909.             // Create header
  1910.             $header "payment_type,timestamp,society_group,trace,message";
  1911.             error_log($header "\n"3$logFilename);
  1912.         }
  1913.         // Log
  1914.         $logMessage $prefixLog ",";
  1915.         $logMessage .= $today->format("Y-m-d H:i:s") . ",";
  1916.         $logMessage .= $societyGroupDisplay ",";
  1917.         $logMessage .= $trace ",";
  1918.         $logMessage .= $msg "\n";
  1919.         error_log($logMessage3$logFilename);
  1920.     }
  1921.     // Plan.io Task #4327
  1922.     // Logs to root/custom_logs/booking/booking_sav_slot
  1923.     public function bookingSavSlot_log($msg$args)
  1924.     {
  1925.         $home $this->getBookingSavSlotLogDir();
  1926.         if (!is_dir($home))    mkdir($home0755true);
  1927.         $today = new \DateTime();
  1928.         $logFile "booking-log-" $today->format("Y-m-d") . ".log";
  1929.         $logFile $home $logFile;
  1930.         $devis = !empty($args['devis']) ? $args['devis'] : null;
  1931.         $timestamp $today->format("[Y-m-d H:i:s]");
  1932.         $log $timestamp;
  1933.         if ($devis !== null)
  1934.         {
  1935.             $log .= "[".$devis->getId()."-".$devis->getRef()."]";
  1936.         }
  1937.         $log .= " " $msg;
  1938.         error_log($log."\n",3,$logFile);
  1939.     }
  1940.     // Plan.io Task #4327
  1941.     // Logs to root/custom_logs/booking/clean_booking_sav_slot
  1942.     public function cleanBookingSavSlot_log($msg)
  1943.     {
  1944.         $home $this->getCleanBookingSavSlotLogDir();
  1945.         if (!is_dir($home))    mkdir($home0755true);
  1946.         $today = new \DateTime();
  1947.         $logFile "clean-booking-log-" $today->format("Y-m-d") . ".log";
  1948.         $logFile $home $logFile;
  1949.         error_log($msg."\n",3,$logFile);
  1950.     }
  1951.     public function errorlog_db($e)
  1952.     {
  1953.         if (!is_object($e))
  1954.         {
  1955.             return null;
  1956.         }
  1957.         if (!($e instanceof \Exception))
  1958.         {
  1959.             return null;
  1960.         }
  1961.         $sql null;
  1962.         $params null;
  1963.         $msg null;
  1964.         if (method_exists($e'getMessage') &&
  1965.             method_exists($e'getQuery') &&
  1966.             method_exists($e->getQuery(), 'getSql') &&
  1967.             method_exists($e->getQuery(), 'getParams'))
  1968.         {
  1969.             $sql $e->getQuery()->getSql();
  1970.             $params print_r($e->getQuery()->getParams(), true);
  1971.             $msg $e->getMessage();
  1972.         }
  1973.         $backTrace debug_backtrace()[1];
  1974.         $method $backTrace['function'];
  1975.         $class $backTrace['class'];
  1976.         // Access handling
  1977.         $access $this->getCurrentUser();
  1978.         $originalUser $this->getOriginalUser();
  1979.         $accessData "";
  1980.         $originalUserData "";
  1981.         if ($access !== null)
  1982.         {
  1983.             $accessData $access->displayForLog();
  1984.         }
  1985.         if ($originalUser !== null)
  1986.         {
  1987.             $originalUserData $originalUser->displayForLog();
  1988.         }
  1989.         $args = array(
  1990.             'recorded_by'        =>    "LogTools::errorlog_db",
  1991.             'class'                =>    $class,
  1992.             'method'            =>    $method,
  1993.             'access'            =>    $accessData,
  1994.             'original_access'    =>    $originalUserData,
  1995.             'msg'                =>    $msg,
  1996.             'query'                =>    $sql,
  1997.             'params'          =>    $params,
  1998.         );
  1999.         $this->plooplog(print_r($argstrue));
  2000.         $this->ouchLogger->error(''$args);
  2001.     }
  2002.     public function errorlog($msg)
  2003.     {
  2004.         $backTrace debug_backtrace()[1];
  2005.         $method $backTrace['function'];
  2006.         $class $backTrace['class'];
  2007.         // Access handling
  2008.         $access $this->getCurrentUser();
  2009.         $originalUser $this->getOriginalUser();
  2010.         $accessData "";
  2011.         $originalUserData "";
  2012.         if ($access !== null)
  2013.         {
  2014.             $accessData $access->displayForLog();
  2015.         }
  2016.         if ($originalUser !== null)
  2017.         {
  2018.             $originalUserData $originalUser->displayForLog();
  2019.         }
  2020.         $args = array(
  2021.             'recorded_by'        =>    "LogTools::errorlog",
  2022.             'class'                =>    $class,
  2023.             'method'            =>    $method,
  2024.             'original_access'    =>    $originalUserData,
  2025.             'msg'                =>    $msg,
  2026.         );
  2027.         if ($access instanceof Access)
  2028.         {
  2029.             $args['access'] = $accessData;
  2030.         }
  2031.         else
  2032.         {
  2033.             if ($access instanceof AccessClient)
  2034.             {
  2035.                 $args['accessClient'] = $accessData;
  2036.             }
  2037.             else
  2038.             {
  2039.                 if ($access instanceof AccessAPI)
  2040.                 {
  2041.                     $args['accessApi'] = $accessData;
  2042.                 }
  2043.             }
  2044.         }
  2045.         $this->plooplog(print_r($argstrue));
  2046.         $this->ouchLogger->error(''$args);
  2047.     }
  2048.     // plan.io #3716
  2049.     public function errorlogApi($msg$accessApi)
  2050.     {
  2051.         $backTrace debug_backtrace()[1];
  2052.         $method $backTrace['function'];
  2053.         $class $backTrace['class'];
  2054.         // Access handling
  2055.         $accessData "";
  2056.         if ($accessApi !== null)
  2057.         {
  2058.             $accessData $accessApi->displayForLog();
  2059.         }
  2060.         $args = array(
  2061.             'class'                =>    $class,
  2062.             'method'            =>    $method,
  2063.             'access'            =>    $accessData,
  2064.             'msg'                =>    $msg,
  2065.         );
  2066.         $this->ouchLogger->error(''$args);
  2067.     }
  2068.     public function getCurrentUser()
  2069.     {
  2070.         $emptyAccess $this->em->getRepository(Access::class)->findOneByEmail(Access::EMPTY_ACCESS);
  2071.         // Get the Access|AccessAPI|AccessClient object returned by the security
  2072.         $access $this->security->getUser();
  2073.         if (empty($access))
  2074.         {
  2075.             // This occurs when the code is execuded by a Command (CRON Task for example)
  2076.             // In this case there is no firewall, and thus no Access|AccessAPI
  2077.             $access $emptyAccess;
  2078.         }
  2079.         else
  2080.         {
  2081.             // The firewall has been bypassed => We have an user provider,
  2082.             // either Access or AccessAPI
  2083.             // Plan.io Task #4327 ... or an AccessClient :)
  2084.             if (!($access instanceof Access) && !($access instanceof AccessAPI) && !($access instanceof AccessClient))
  2085.             {
  2086.                 // This should not happen, but hey, life is weird, who knows
  2087.                 // Even VSCode proved to be worse than Atom ;)
  2088.                 $access $emptyAccess;
  2089.             }
  2090.         }
  2091.         // Plan.io Task #3946
  2092.         if ($access instanceof AccessAPI)
  2093.         {
  2094.             // Almost all AccessAPI have a corresponding Access, so retrive it
  2095.             $access $access->getAccess();
  2096.         }
  2097.         return $access;
  2098.     }
  2099.     // https://symfony.com/doc/5.4/security/impersonating_user.html
  2100.     // This is also in AdminVoter
  2101.     // This is also in Logger
  2102.     // This is also in LogTools
  2103.     // This is also in AccessTools
  2104.     // This is also in AlertTools
  2105.     public function getOriginalUser()
  2106.     {
  2107.         $originalUser null;
  2108.         // #3251 Fix to avoid infinity loop
  2109.         $currentUser $this->getCurrentUser();
  2110.         if ($currentUser === null || $currentUser->getEmail() == Access::EMPTY_ACCESS)
  2111.         {
  2112.             return null;
  2113.         }
  2114.         $token $this->security->getToken();
  2115.         if ($token instanceof SwitchUserToken)
  2116.         {
  2117.             $originalUser $token->getOriginalToken()->getUser();
  2118.         }
  2119.         return $originalUser;
  2120.     }
  2121.     public function generateAlphaNumCode($length)
  2122.     {
  2123.         $lowercase "qwertyuiopasdfghjklzxcvbnm";
  2124.         $numbers "1234567890";
  2125.         $randomCode "";
  2126.         $length abs($length);
  2127.         $lengthSlice $length 2;
  2128.         $max strlen($lowercase) - 1;
  2129.         for ($x 0$x $lengthSlice$x++)
  2130.         {
  2131.             $i random_int(0$max);
  2132.             $randomCode .= $lowercase[$i];
  2133.         }
  2134.         $max strlen($numbers) - 1;
  2135.         for ($x 0$x $lengthSlice$x++)
  2136.         {
  2137.             $i random_int(0$max);
  2138.             $randomCode .= $numbers[$i];
  2139.         }
  2140.         return str_shuffle($randomCode);
  2141.     }
  2142.     public function generateUniqueGuardLogFileName()
  2143.     {
  2144.         $today = new \DateTime();
  2145.         $prefix "guard_log_".$today->format("Y_m_d")."_";
  2146.         $code $this->generateAlphaNumCode(30);
  2147.         $logFileName $prefix $code ".log";
  2148.         return $logFileName;
  2149.     }
  2150.     public function fetchGuardLogFile($logFileName)
  2151.     {
  2152.         $logPath $this->getGuardGlobalLogsDir();
  2153.         if (!file_exists($logPath))
  2154.         {
  2155.             if (!mkdir($logPath))
  2156.             {
  2157.                 return null;
  2158.             }
  2159.         }
  2160.         $logFile $logPath.$logFileName;
  2161.         return $logFile;
  2162.     }
  2163.     public function formatGuardLogFile($logFile)
  2164.     {
  2165.         if (!file_exists($logFile))
  2166.         {
  2167.             return "";
  2168.         }
  2169.         $log file_get_contents($logFile);
  2170.         if ($log)
  2171.         {
  2172.             $log str_replace("\n""<br>"$log);
  2173.             $log str_replace("not found""<span class='text-danger'>not found</span>"$log);
  2174.             $log str_replace("inactive""<span class='text-danger'>inactive</span>"$log);
  2175.             $log str_replace("error""<span class='text-danger'><strong>error</strong></span>"$log);
  2176.             $log str_replace("ADD""<span style='color:#39c300'><strong>ADD</strong></span>"$log);
  2177.             $log str_replace("DENY""<span style='color:#ff731d'><strong>DENY</strong></span>"$log);
  2178.             $log str_replace("ERROR""<span style='color:#da0000'><strong>ERROR</strong></span>"$log);
  2179.             $log str_replace("UPDATE""<span style='color:#af0076'><strong>UPDATE</strong></span>"$log);
  2180.             $log str_replace("SYNC""<span style='color:#d800a6'><strong>SYNC</strong></span>"$log);
  2181.             $log str_replace("DEACTIVATE""<span style='color:#645caa'><strong>DEACTIVATE</strong></span>"$log);
  2182.             $log str_replace("ACTIVATE""<span style='color:#645caa'><strong>ACTIVATE</strong></span>"$log);
  2183.             $log str_replace("REMOVE""<span style='color:#F94A29'><strong>REMOVE</strong></span>"$log);
  2184.             $log str_replace("DELETE""<span style='color:#F94A29'><strong>DELETE</strong></span>"$log);
  2185.         }
  2186.         return $log;
  2187.     }
  2188.     public function loadGuardFile($logFile$fileName)
  2189.     {
  2190.         $log null;
  2191.         $matrix null;
  2192.         // Get the configuration file
  2193.         $webPath $this->getGuardConfigDir();
  2194.         $matrixFile $webPath $fileName;
  2195.         if (!file_exists($matrixFile))
  2196.         {
  2197.             $log = array(
  2198.                 "status"        =>    false,
  2199.                 "error"            =>    "config_file_does_not_exist",
  2200.                 "info"            =>    $matrixFile,
  2201.             );
  2202.         }
  2203.         else
  2204.         {
  2205.             // Read its contents
  2206.             $matrix file_get_contents($matrixFile);
  2207.             if (!$matrix)
  2208.             {
  2209.                 $log = array(
  2210.                     "status"        =>    false,
  2211.                     "error"            =>    "config_file_could_not_be_read",
  2212.                     "info"            =>    $matrixFile,
  2213.                 );
  2214.             }
  2215.             else
  2216.             {
  2217.                 // If we are here it means that all went well
  2218.                 return $matrix;
  2219.             }
  2220.         }
  2221.         if ($log !== null)
  2222.         {
  2223.             // Something went wrong
  2224.             // Get the error and translate it
  2225.             $error $this->translator->trans($log["error"]);
  2226.             $error .= " : ";
  2227.             $error .= $log["info"];
  2228.             // Save it to the log file, if any
  2229.             if ($logFile !== null)
  2230.             {
  2231.                 error_log("\n".$error3$logFile);
  2232.             }
  2233.             // Log it to global logs also
  2234.             $this->errorlog($error);
  2235.             return null;
  2236.         }
  2237.         // If we are here it means that all went well
  2238.         return $matrix;
  2239.     }
  2240.     public function loadGuardConfigFile($logFile$fileName)
  2241.     {
  2242.         $log null;
  2243.         $matrix null;
  2244.         // Get the configuration file
  2245.         $webPath $this->getGuardConfigDir();
  2246.         $matrixFile $webPath $fileName;
  2247.         if (!file_exists($matrixFile))
  2248.         {
  2249.             $log = array(
  2250.                 "status"        =>    false,
  2251.                 "error"            =>    "config_file_does_not_exist",
  2252.                 "info"            =>    $matrixFile,
  2253.             );
  2254.         }
  2255.         else
  2256.         {
  2257.             // Read its contents
  2258.             $matrix file_get_contents($matrixFile);
  2259.             if (!$matrix)
  2260.             {
  2261.                 $log = array(
  2262.                     "status"        =>    false,
  2263.                     "error"            =>    "config_file_could_not_be_read",
  2264.                     "info"            =>    $matrixFile,
  2265.                 );
  2266.             }
  2267.             else
  2268.             {
  2269.                 // Parse it
  2270.                 $yamlparser = new \Symfony\Component\Yaml\Parser();
  2271.                 $matrix $yamlparser->parse($matrix);
  2272.                 if (!$matrix || empty($matrix))
  2273.                 {
  2274.                     $log = array(
  2275.                         "status"        =>    false,
  2276.                         "error"            =>    "config_file_could_not_be_parsed",
  2277.                         "info"            =>    $matrixFile,
  2278.                     );
  2279.                 }
  2280.             }
  2281.         }
  2282.         if ($log !== null)
  2283.         {
  2284.             // Something went wrong
  2285.             // Get the error and translate it
  2286.             $error $this->translator->trans($log["error"]);
  2287.             $error .= " : ";
  2288.             $error .= $log["info"];
  2289.             // Save it to the log file, if any
  2290.             if ($logFile !== null)
  2291.             {
  2292.                 error_log("\n".$error3$logFile);
  2293.             }
  2294.             // Log it to global logs also
  2295.             $this->errorlog($error);
  2296.             return null;
  2297.         }
  2298.         // If we are here it means that all went well
  2299.         return $matrix;
  2300.     }
  2301.     // Plan.io Task #4105
  2302.     public function loadSocietyGroupDeleteScript(SocietyGroup $societyGroup)
  2303.     {
  2304.         $matrix null;
  2305.         $fileName "society_group_delete.sql";
  2306.         // Get the configuration file
  2307.         $webPath $this->getGuardConfigDir();
  2308.         $matrixFile $webPath $fileName;
  2309.         if (!file_exists($matrixFile))
  2310.         {
  2311.             return array(
  2312.                 "status"        =>    false,
  2313.                 "error"            =>    "config_file_does_not_exist",
  2314.                 "info"            =>    $matrixFile,
  2315.             );
  2316.         }
  2317.         else
  2318.         {
  2319.             // Read its contents
  2320.             $matrix file_get_contents($matrixFile);
  2321.             if (!$matrix)
  2322.             {
  2323.                 return array(
  2324.                     "status"        =>    false,
  2325.                     "error"            =>    "config_file_could_not_be_read",
  2326.                     "info"            =>    $matrixFile,
  2327.                 );
  2328.             }
  2329.             else
  2330.             {
  2331.                 // If we are here it means that all went well
  2332.                 // Replace SGID with $societyGroup->id
  2333.                 $matrix str_replace("SGID"$societyGroup->getId(), $matrix);
  2334.                 return array(
  2335.                     "status"        =>    true,
  2336.                     "data"            =>    $matrix,
  2337.                 );
  2338.             }
  2339.         }
  2340.         return array(
  2341.             "status"        =>    false,
  2342.             "error"            =>    "unknown_error",
  2343.             "info"            =>    $matrixFile,
  2344.         );
  2345.     }
  2346.     // Types : add, deny, error, update, sync, activate, deactivate
  2347.     // add : #39c300 rgb(57,195,0)
  2348.     // deny : #ff731d rgb(255,115,29)
  2349.     // error : #da0000 rgb(218,0,0)
  2350.     // update : #af0076 rgb(175,0,118)
  2351.     // sync : #d800a6 rgb(216,0,166)
  2352.     // activate : #645caa rgb(100,92,170)
  2353.     // deactivate : #645caa rgb(160,132,202)
  2354.     public function guardLog($logFile$msg$type null)
  2355.     {
  2356.         if ($logFile === null)
  2357.         {            
  2358.             return false;
  2359.         }
  2360.         $backTrace debug_backtrace();
  2361.         // When the logging is done by the SocietyGroupGenerator
  2362.         // Allow the deny statements
  2363.         // Skip them otherwise
  2364.         $allowDeny false;
  2365.         if (in_array($type, array("deny")))
  2366.         {
  2367.             if (isset($backTrace[2]))
  2368.             {
  2369.                 $method $backTrace[2]['function'];
  2370.                 // $this->plooplog("method(2) = ".$method);
  2371.                 if ($method == 'createSocietyGroupWithGuard')
  2372.                 {
  2373.                     $allowDeny true;
  2374.                 }
  2375.             }
  2376.         }
  2377.         if (in_array($type, array("deny")) && !$allowDeny)
  2378.         {
  2379.             return false;
  2380.         }
  2381.         $backTrace debug_backtrace()[1];
  2382.         $method $backTrace['function'];
  2383.         $class $backTrace['class'];
  2384.         $class str_replace("App\\Guardian\\"""$class);
  2385.         $class str_replace("App\\Services\\"""$class);
  2386.         $class str_replace("App\\Controller\\"""$class);
  2387.         if ($type !== null)
  2388.         {
  2389.             $msg "\n" strtoupper($type) . " ; " $class " ; " $method " ; " $msg;
  2390.         }
  2391.         else
  2392.         {
  2393.             $msg "\n" $class " ; " $method " ; " $msg;
  2394.         }
  2395.         error_log($msg3$logFile);
  2396.         return true;
  2397.     }
  2398.     public function logInvoiceMissingDevisProduct(Invoice $invoiceDevis $devis$msg)
  2399.     {
  2400.         $logFile $this->getInvoiceMissingDevisProductsLogsDir().$invoice->getSocietyGroup()->getId().".log";
  2401.         $today = new \DateTime();
  2402.         $timestamp $today->format("Y-m-d H:i:s");
  2403.         $invoiceId $invoice->getId();
  2404.         $invoiceRef $invoice->getRef();
  2405.         $devisId $devis->getId();
  2406.         $devisRef $devis->getRef();
  2407.         $output "\n[$timestamp][$invoiceId][$invoiceRef][$devisId][$devisRef]$msg";
  2408.         error_log($output3$logFile);
  2409.     }
  2410.     //--------------------------------------------------------------------------
  2411.     // Plan.io Task #3922
  2412.     public function camelToSnakeCase($text)
  2413.     {
  2414.         return strtolower(preg_replace(['/([a-z\d])([A-Z])/''/([^_])([A-Z][a-z])/'], '$1_$2'$text));
  2415.     }
  2416.     public function handleLoggingData($entity)
  2417.     {
  2418.         $info null;
  2419.         $specialAuthor null;
  2420.         $ignore false;
  2421.         $action null;
  2422.         if (method_exists($entity"getLoggingData"))
  2423.         {
  2424.             $loggingData $entity->getLoggingData();
  2425.             // $this->ploopLog("[LogTools][handleLoggingData] --------------------------------------------------");
  2426.             // $this->ploopLog("[LogTools][handleLoggingData] entity = ".$entity->displayForLog());
  2427.             // $this->ploopLog("[LogTools][handleLoggingData] loggingData = ".print_r($loggingData, true));
  2428.             if (!empty($loggingData) && is_array($loggingData))
  2429.             {
  2430.                 if (array_key_exists('action'$loggingData))
  2431.                 {
  2432.                     $action $loggingData['action'];
  2433.                 }
  2434.                 if (array_key_exists('info'$loggingData))
  2435.                 {
  2436.                     $info $loggingData['info'];
  2437.                 }
  2438.                 if (array_key_exists('special_author'$loggingData))
  2439.                 {
  2440.                     $specialAuthor $loggingData['special_author'];
  2441.                 }
  2442.                 if (array_key_exists('ignore'$loggingData))
  2443.                 {
  2444.                     $ignore boolval($loggingData['ignore']);
  2445.                 }
  2446.             }
  2447.         }
  2448.         // $this->ploopLog("[LogTools][handleLoggingData] info = ".$info);
  2449.         // if ($ignore) $this->ploopLog("[LogTools][handleLoggingData] ignore = true");
  2450.         // else $this->ploopLog("[LogTools][handleLoggingData] ignore = false");
  2451.         // $this->ploopLog("[LogTools][handleLoggingData] --------------------------------------------------");
  2452.         return array(
  2453.             'action'            => $action,
  2454.             'info'              => $info,
  2455.             'special_author'    => $specialAuthor,
  2456.             'ignore'            => $ignore,
  2457.         );
  2458.     }
  2459.     //--------------------------------------------------------------------------
  2460.     // Plan.io Task #3922
  2461.     public function getLogPathForMission(Mission $mission)
  2462.     {
  2463.         $originalLogPath $this->getDMS_MissionLogsDir();
  2464.         $societyGroup $mission->getSocietyGroupAuthor();
  2465.         if ($societyGroup === null)
  2466.         {
  2467.             return null;
  2468.         }
  2469.         $societyGroupId $societyGroup->getId();
  2470.         $societyGroupRef $societyGroup->getInternalRef();
  2471.         if (empty($societyGroupId) || empty($societyGroupRef))
  2472.         {
  2473.             return null;
  2474.         }            
  2475.         // Craft folder name
  2476.         $logFolderName $societyGroupId."_".$societyGroupRef;
  2477.         $logPath $originalLogPath.$logFolderName."/";
  2478.         // Craft file name
  2479.         $id $mission->getId();
  2480.         $logFileName "mission_log_".$id.".csv";        
  2481.         
  2482.         $logFile $logPath.$logFileName;
  2483.         if (file_exists($logFile))
  2484.         {
  2485.             return $logFile;
  2486.         }
  2487.         return null;
  2488.     }
  2489.     // Plan.io Task #3922
  2490.     public function getLogPathForClient(Client $client)
  2491.     {
  2492.         $originalLogPath $this->getDMS_ClientLogsDir();
  2493.         $societyGroup $client->getSocietyGroup();
  2494.         if ($societyGroup === null)
  2495.         {
  2496.             return null;
  2497.         }
  2498.         $societyGroupId $societyGroup->getId();
  2499.         $societyGroupRef $societyGroup->getInternalRef();
  2500.         if (empty($societyGroupId) || empty($societyGroupRef))
  2501.         {
  2502.             return null;
  2503.         }            
  2504.         // Craft folder name
  2505.         $logFolderName $societyGroupId."_".$societyGroupRef;
  2506.         $logPath $originalLogPath.$logFolderName."/";
  2507.         // Craft file name
  2508.         $id $client->getId();
  2509.         $logFileName "client_log_".$id.".csv";        
  2510.         
  2511.         $logFile $logPath.$logFileName;
  2512.         if (file_exists($logFile))
  2513.         {
  2514.             return $logFile;
  2515.         }
  2516.         return null;
  2517.     }
  2518.     /**
  2519.      * Returns the path to the CSV log file for the given human resource, or null if not found.
  2520.      * Path pattern: DMS/Logs/HumanResource/{societyGroupId}_{societyGroupRef}/human_resource_log_{id}.csv
  2521.      */
  2522.     public function getLogPathForHumanResource(HumanResource $humanResource)
  2523.     {
  2524.         $originalLogPath $this->getDMS_HumanResourceLogsDir();
  2525.         $societyGroup $humanResource->getSocietyGroup();
  2526.         if ($societyGroup === null)
  2527.         {
  2528.             return null;
  2529.         }
  2530.         $societyGroupId $societyGroup->getId();
  2531.         $societyGroupRef $societyGroup->getInternalRef();
  2532.         if (empty($societyGroupId) || empty($societyGroupRef))
  2533.         {
  2534.             return null;
  2535.         }
  2536.         $logFolderName $societyGroupId."_".$societyGroupRef;
  2537.         $logPath $originalLogPath.$logFolderName."/";
  2538.         $id $humanResource->getId();
  2539.         $logFileName "human_resource_log_".$id.".csv";
  2540.         $logFile $logPath.$logFileName;
  2541.         if (file_exists($logFile))
  2542.         {
  2543.             return $logFile;
  2544.         }
  2545.         return null;
  2546.     }
  2547.     // Plan.io Task #4624
  2548.     public function getLogPathForProjectNotebook(ProjectNotebook $notebook)
  2549.     {
  2550.         $originalLogPath $this->getDMS_ProjectManagerNotebookLogsDir();
  2551.         $societyGroup $notebook->getSocietyGroup();
  2552.         if ($societyGroup === null)
  2553.         {
  2554.             return null;
  2555.         }
  2556.         $societyGroupId $societyGroup->getId();
  2557.         $societyGroupRef $societyGroup->getInternalRef();
  2558.         if (empty($societyGroupId) || empty($societyGroupRef))
  2559.         {
  2560.             return null;
  2561.         }            
  2562.         // Craft folder name
  2563.         $logFolderName $societyGroupId."_".$societyGroupRef;
  2564.         $logPath $originalLogPath.$logFolderName."/";
  2565.         // Craft file name
  2566.         $id $notebook->getId();
  2567.         $logFileName "project_notebook_log_".$id.".csv";            
  2568.         
  2569.         $logFile $logPath.$logFileName;
  2570.         if (file_exists($logFile))
  2571.         {
  2572.             return $logFile;
  2573.         }
  2574.         return null;
  2575.     }
  2576.     
  2577.     /**
  2578.      * Reads the logging CSV produced by Logging::logToFile() into an array of LogCsvRecord DTOs.
  2579.      * File format: semicolon-delimited, first line may be blank, then header row, then data rows.
  2580.      *
  2581.      * #3922 : This was generated by Cursor => Review and Clean
  2582.      * 
  2583.      * @return LogCsvRecord[]
  2584.      */
  2585.     public function readLoggingCsv(string $filePath): array
  2586.     {
  2587.         // Ensure the file exists and is readable before attempting to load it
  2588.         if (!is_readable($filePath))
  2589.         {
  2590.             return [];
  2591.         }
  2592.         // Load the entire file content (CSV may be written with mixed line endings by error_log)
  2593.         $raw file_get_contents($filePath);
  2594.         if ($raw === false)
  2595.         {
  2596.             return [];
  2597.         }
  2598.         // Split into lines using any common newline sequence (Unix, Windows, legacy Mac)
  2599.         $allLines preg_split('/\r\n|\r|\n/'$raw);
  2600.         if ($allLines === false)
  2601.         {
  2602.             return [];
  2603.         }
  2604.         // Drop empty lines so the first non-empty line is the header (Logging writes a leading newline)
  2605.         $nonEmptyLines array_values(array_filter($allLines, static function (string $line): bool
  2606.         {
  2607.             return trim($line) !== '';
  2608.         }));
  2609.         if (count($nonEmptyLines) < 2)
  2610.         {
  2611.             return [];
  2612.         }
  2613.         // First non-empty line is the semicolon-separated header row; normalize and remove empty cells
  2614.         $headerLine $nonEmptyLines[0];
  2615.         $headers array_values(array_filter(array_map('trim'explode(';'$headerLine)), static function (string $h): bool {
  2616.             return $h !== '';
  2617.         }));
  2618.         // Parse each remaining line as a data row and map to a LogCsvRecord DTO
  2619.         $records = [];
  2620.         for ($i 1$n count($nonEmptyLines); $i $n$i++)
  2621.         {
  2622.             $values explode(';'$nonEmptyLines[$i]);
  2623.             $records[] = LogCsvRecord::fromRow($headers$values);
  2624.         }
  2625.         return $records;
  2626.     }
  2627.     /**
  2628.      * Streams the logging CSV produced by Logging::logToFile() as LogCsvRecord DTOs.
  2629.      * Use this for large files (e.g. tens of MB) to avoid loading the whole file into memory.
  2630.      * File format: semicolon-delimited, first line may be blank, then header row, then data rows.
  2631.      * 
  2632.      * #3922 : This was generated by Cursor => Review and Clean
  2633.      * Working, but still too much data to output
  2634.      * DOM loading is extremly slow ... and becomes not responsive
  2635.      *
  2636.      * @return \Generator<int, LogCsvRecord, void, void>
  2637.      *
  2638.      * Example:
  2639.      *   foreach ($logTools->readLoggingCsvXXL('/path/to/file.csv') as $record) {
  2640.      *       // process $record
  2641.      *   }
  2642.      */
  2643.     public function readLoggingCsvXXL(string $filePath): \Generator
  2644.     {
  2645.         // Ensure the file exists and is readable before opening
  2646.         if (!is_readable($filePath))
  2647.         {
  2648.             return;
  2649.         }
  2650.         $handle fopen($filePath'rb');
  2651.         if ($handle === false)
  2652.         {
  2653.             return;
  2654.         }
  2655.         try
  2656.         {
  2657.             // Read line by line (fgets stops at \n; \r\n or \r are included and trimmed below)
  2658.             // so only one line is in memory at a time.
  2659.             $headers null;
  2660.             while (($line fgets($handle)) !== false)
  2661.             {
  2662.                 $line trim($line);
  2663.                 if ($line === '')
  2664.                 {
  2665.                     continue;
  2666.                 }
  2667.                 // First non-empty line is the header; parse and store for mapping data rows
  2668.                 if ($headers === null)
  2669.                 {
  2670.                     $headers array_values(array_filter(
  2671.                         array_map('trim'explode(';'$line)),
  2672.                         static function (string $h): bool {
  2673.                             return $h !== '';
  2674.                         }
  2675.                     ));
  2676.                     continue;
  2677.                 }
  2678.                 // Subsequent non-empty lines are data rows: parse and yield one record
  2679.                 $values explode(';'$line);
  2680.                 yield LogCsvRecord::fromRow($headers$values);
  2681.             }
  2682.         }
  2683.         finally
  2684.         {
  2685.             // Always close the handle when the generator is exhausted or the consumer stops iterating
  2686.             fclose($handle);
  2687.         }
  2688.     }
  2689. }