src/Application/Internit/LeadBundle/Controller/ProductAdminController.php line 203

Open in your IDE?
  1. <?php
  2. namespace App\Application\Internit\LeadBundle\Controller;
  3. // Include PhpSpreadsheet required namespaces
  4. use App\Application\Internit\RealEstateBundle\Entity\RealEstate;
  5. use App\Application\Sonata\UserBundle\Entity\User;
  6. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  7. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  8. use PhpOffice\PhpSpreadsheet\Writer\Csv;
  9. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  10. use Symfony\Component\HttpFoundation\StreamedResponse;
  11. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  12. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  16. use App\Application\Internit\ContentBundle\Controller\CRUD;
  17. use App\Application\Internit\LeadBundle\DTO\ProductUserDTO;
  18. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  19. use App\Application\Internit\LeadBundle\Entity\ProductUser;
  20. use App\Application\Internit\LeadBundle\Entity\realStatePercent;
  21. use App\Application\Internit\LeadBundle\Entity\Product;
  22. use App\Application\Internit\LeadBundle\Entity\ProductLog;
  23. /**
  24.  * Client Admin controller.
  25.  *
  26.  * @Route("/admin/internit/lead/product")
  27.  */
  28. class ProductAdminController extends CRUD
  29. {
  30.     public $base = "@ApplicationInternit/LeadBundle/Resources/views/Product/";
  31.     public $bundle = "ApplicationInternitLeadBundle:Product";
  32.     private $listActionRoles            = array('ROLE_CONSTRUTORA', 'ROLE_DIRETORIA', 'ROLE_IMOBILIARIA');
  33.     private $createActionRoles          = array('ROLE_CONSTRUTORA');
  34.     private $editActionRoles            = array('ROLE_CONSTRUTORA');
  35.     private $showActionRoles            = array('ROLE_CONSTRUTORA', 'ROLE_DIRETORIA', 'ROLE_IMOBILIARIA');
  36.     private $exportFilteredActionRoles  = array('ROLE_CONSTRUTORA', 'ROLE_DIRETORIA', 'ROLE_IMOBILIARIA');
  37.     public function listAction($order = array('id' => 'DESC'))
  38.     {
  39.         if (!$this->get('security.token_storage')->getToken()->getUser()->hasRole($this->listActionRoles)) 
  40.         {
  41.             return $this->renderWithExtraParams("@ApplicationInternit/ContentBundle/Resources/views/permission.html.twig");    
  42.         }  
  43.         return parent::listAction($order);
  44.     }
  45.     
  46.     public function createAction()
  47.     {     
  48.         if (!$this->get('security.token_storage')->getToken()->getUser()->hasRole($this->createActionRoles)) 
  49.         {
  50.             return $this->renderWithExtraParams("@ApplicationInternit/ContentBundle/Resources/views/permission.html.twig");    
  51.         }        
  52.         $request = $this->getRequest();
  53.         // the key used to lookup the template
  54.         $templateKey = 'edit';
  55.         $this->admin->checkAccess('create');
  56.         
  57.         $class = new \ReflectionClass($this->admin->hasActiveSubClass() ? $this->admin->getActiveSubClass() : $this->admin->getClass());
  58.         
  59.         $newObject = $this->admin->getNewInstance();
  60.         $preResponse = $this->preCreate($request, $newObject);
  61.         if (null !== $preResponse) {
  62.             return $preResponse;
  63.         }
  64.         $this->admin->setSubject($newObject);
  65.         $form = $this->admin->getForm();
  66.         
  67.         $form->setData($newObject);
  68.         $form->handleRequest($request);
  69.         
  70.         if ($form->isSubmitted()) {
  71.             $isFormValid = $form->isValid();            
  72.             // persist if the form was valid and if in preview mode the preview was approved
  73.             if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) {
  74.                 $this->persistImageApresentation($form);
  75.                 $submittedObject = $form->getData();
  76.                 $this->admin->setSubject($submittedObject);
  77.                 $this->admin->checkAccess('create', $submittedObject);                
  78.                 try {
  79.                     $token = md5(random_bytes(10).date('dmYHis'));
  80.                     $realStatePercentList = $submittedObject->getRealStatePercents();
  81.                     $productUserList = $submittedObject->getProductUsers();
  82.                     
  83.                     $newObject->setProductUsers(null);
  84.                     $newObject->setToken($token);
  85.                     if($realStatePercentList)
  86.                     {
  87.                         //Checa percent = 100%
  88.                         $totalPercent = 0;
  89.                         foreach ($realStatePercentList as $rsPercent) {
  90.                             $totalPercent += $rsPercent->getPercent();
  91.                         }
  92.                         if($totalPercent != 100)
  93.                         {
  94.                             
  95.                             $this->get('session')->getFlashBag()->set('flash_create_error', 'As porcentagens das imobiliárias devem somar 100%');
  96.                             return $this->redirectToRoute('admin_internit_lead_product_create');
  97.          
  98.                         }
  99.                         foreach ($realStatePercentList as $imob => $rsPercent) {
  100.                             $imobComEspaco = str_replace(
  101.                                 array('_'),
  102.                                 ' ',
  103.                                 $imob
  104.                             );
  105.                             $realEstate = $this->getDoctrine()->getRepository('ApplicationInternitRealEstateBundle:RealEstate')->findOneByName($imobComEspaco);
  106.                             if($realEstate){
  107.                                 $rsPercent->setProduct($newObject);
  108.                                 $rsPercent->setRealEstate($realEstate);
  109.                                 
  110.                                 $newRealStatePercent = $this->admin->create($rsPercent);
  111.                                 $newObject->addRealStatePercents($newRealStatePercent);
  112.                             }
  113.                         }
  114.                     }
  115.                     if($productUserList)
  116.                     {
  117.                         $i=0;
  118.                         foreach ($productUserList as $user) {
  119.                             $userImob = explode(':',$user);
  120.                             $corretor = $this->getDoctrine()->getRepository('ApplicationSonataUserBundle:User')->findOneById($userImob[1]);
  121.                             $realEstate = $this->getDoctrine()->getRepository('ApplicationInternitRealEstateBundle:RealEstate')->findOneById($userImob[0]);
  122.                             if($corretor && $realEstate){
  123.                                 
  124.                                 $productUser = new ProductUser();
  125.                                 $productUser->setUser($corretor);
  126.                                 $productUser->setRealEstate($realEstate);
  127.                                 $productUser->setProduct($newObject);
  128.                                 $productUser->setPosition($i);
  129.                                 $newProductUser = $this->admin->create($productUser);
  130.                                 $newObject->addProductUsers($newProductUser);
  131.                                 $i++;
  132.                             }
  133.                         }
  134.                     }
  135.                     $newObject = $this->admin->create($newObject);
  136.                                         
  137.                     $this->get('session')->getFlashBag()->set('flash_create_success', 'Mensagem enviada com sucesso');
  138.                                         
  139.                     // redirect to edit mode
  140.                     return $this->redirectTo($newObject);
  141.                 } catch (ModelManagerException $e) {
  142.                     $this->handleModelManagerException($e);
  143.                     $isFormValid = false;
  144.                 }
  145.             }
  146.             
  147.             // show an error message if the form failed validation
  148.             if (!$isFormValid) {
  149.                 if (!$this->isXmlHttpRequest()) 
  150.                 {        
  151.                     $errors = array();
  152.                     foreach ($form->getErrors(true) as $error) {
  153.                         $errors[] = $error->getMessage();
  154.                     } 
  155.                       
  156.                     $this->get('session')->getFlashBag()->set('flash_create_error', implode('<br>', $errors));
  157.                 }
  158.             }
  159.         }
  160.         $formView = $form->createView();
  161.     
  162.         return $this->renderWithExtraParams($this->base."create.html.twig", [
  163.             'form' => $formView
  164.         ], null);     
  165.     }
  166.     public function saveExtraLeadsAction(Request $request)
  167.     {
  168.         $realEstate = $request->get('realStateId');
  169.         $extraLeads = $request->get('extraLeads');
  170.         $productId = $request->get('product');
  171.         $product = $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:realStatePercent')->findOneBy(['product' => $productId, 'realEstate' => $realEstate]);
  172.         if($product){
  173.             $product->setExtraLeads($extraLeads);
  174.             $em = $this->getDoctrine()->getManager();
  175.             $em->persist($product);
  176.             $em->flush();
  177.         }
  178.         $route = $request->headers->get('referer');
  179.         return $this->redirect($route);
  180.     }
  181.     public function saveLogs($productId, Request $request)
  182.     {
  183.         $formData = $request->request->all();
  184.         $formKey = array_key_first($formData);
  185.         $users = $formData[$formKey]['productUsers'];
  186.         $percents = $formData[$formKey]['realStatePercents'];
  187.         $product = $formData[$formKey]['name'];
  188.         
  189.         $data = [];
  190.         // Busca em lote em vez de 2 consultas por corretor no loop -- com produtos
  191.         // que tem muitos corretores/imobiliarias, isso sozinho gerava centenas de
  192.         // consultas so nessa etapa, aumentando a janela de colisao de lock com
  193.         // outras transacoes tocando a mesma linha do produto.
  194.         $usersParsed = [];
  195.         foreach ($users as $user) {
  196.             $usersParsed[] = explode(':', $user);
  197.         }
  198.         $realEstateIds = array_unique(array_column($usersParsed, 0));
  199.         $userIds = array_unique(array_column($usersParsed, 1));
  200.         $realEstatesById = [];
  201.         foreach ($this->getDoctrine()->getRepository('ApplicationInternitRealEstateBundle:RealEstate')->findBy(['id' => $realEstateIds]) as $re) {
  202.             $realEstatesById[$re->getId()] = $re;
  203.         }
  204.         $corretoresById = [];
  205.         foreach ($this->getDoctrine()->getRepository('ApplicationSonataUserBundle:User')->findBy(['id' => $userIds]) as $u) {
  206.             $corretoresById[$u->getId()] = $u;
  207.         }
  208.         foreach ($usersParsed as $user) {
  209.             $realEstate = $realEstatesById[$user[0]] ?? null;
  210.             $corretor = $corretoresById[$user[1]] ?? null;
  211.             if (!$realEstate || !$corretor) {
  212.                 continue;
  213.             }
  214.             $index = str_replace(" ", "_", $this->removeAcentos($realEstate->getName()));
  215.             $data[$index]["corretores"][] = $corretor->getFirstname();
  216.         }
  217.         
  218.         foreach($percents as $key=>$percent){
  219.             if($percent['percent'] > 0 && !is_numeric($key) )
  220.             {
  221.                 $data[$key]['percent'] = $percent['percent'];
  222.                 // dump($key);
  223.             }
  224.             
  225.         }
  226.         // dump($percents);
  227.         // dump($data); exit;;/
  228.         
  229.         // $finalData["product"] = $product;
  230.         $finalData["LogData"] = date('d/m/Y H:i:s');
  231.         $finalData["Imobiliarias"] = [];
  232.         foreach($data as $key => $val){
  233.             $percent = isset($val["percent"]) ? $val["percent"] : 0;
  234.             unset($val["percent"]); // Remove o campo interno
  235.             $finalData["Imobiliarias"][$key . " " . $percent . "%"] = $val;
  236.         }
  237.         $productObject = $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:Product')->findOneById($productId);
  238.         //dump($productObject); exit;
  239.         $dataJson = json_encode($finalData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
  240.         $log = new ProductLog();
  241.         $log->setProduct($productObject);
  242.         $log->setLog($dataJson);
  243.         $log->setType("CAMPANHA");
  244.         $log->setCreatedAt(new \DateTime());
  245.         $em = $this->getDoctrine()->getManager();
  246.         $em->persist($log);
  247.         
  248.     }
  249.     function removeAcentos($string) {
  250.         $acentos = [
  251.             'á','à','ã','â','ä','é','è','ê','ë','í','ì','î','ï','ó','ò','õ','ô','ö','ú','ù','û','ü','ç',
  252.             'Á','À','Ã','Â','Ä','É','È','Ê','Ë','Í','Ì','Î','Ï','Ó','Ò','Õ','Ô','Ö','Ú','Ù','Û','Ü','Ç'
  253.         ];
  254.         $semAcentos = [
  255.             'a','a','a','a','a','e','e','e','e','i','i','i','i','o','o','o','o','o','u','u','u','u','c',
  256.             'A','A','A','A','A','E','E','E','E','I','I','I','I','O','O','O','O','O','U','U','U','U','C'
  257.         ];
  258.         return str_replace($acentos, $semAcentos, $string);
  259.     }
  260.     public function editAction($id = null)
  261.     {
  262.         if (!$this->get('security.token_storage')->getToken()->getUser()->hasRole($this->editActionRoles)) 
  263.         {
  264.             return $this->renderWithExtraParams("@ApplicationInternit/ContentBundle/Resources/views/permission.html.twig");    
  265.         }
  266.         // return parent::editAction($id = null);
  267.         $request = $this->getRequest();        
  268.         $templateKey = 'edit';
  269.         $id = $request->get($this->admin->getIdParameter());       
  270.         $existingObject = $this->admin->getObject($id);
  271.         if (!$existingObject) {
  272.             throw $this->createNotFoundException(sprintf('unable to find the object with id: %s', $id));
  273.         }
  274.         $form = $this->admin->getForm();        
  275.         
  276.         
  277.         $form->setData($existingObject);
  278.         $form->handleRequest($request);  
  279.              
  280.         
  281.         if ($form->isSubmitted()) {
  282.             $isFormValid = $form->isValid();
  283.             $submittedObject = $form->getData();
  284.             $this->admin->setSubject($submittedObject);
  285.             
  286.             try {
  287.                 $this->saveLogs($id, $request);
  288.                
  289.                 $realStatePercentList = $submittedObject->getRealStatePercents();
  290.                 //Checa percent = 100%
  291.                 $totalPercent = 0;
  292.                 foreach ($realStatePercentList as $imob => $rsPercent) {
  293.                     if (is_string($imob)) {
  294.                         $totalPercent += $rsPercent->getPercent();
  295.                     }
  296.                 }
  297.                 if($totalPercent != 100)
  298.                 {
  299.                     $this->get('session')->getFlashBag()->set('flash_create_error', 'As porcentagens das imobiliárias devem somar 100%');
  300.                     $isFormValid = false;
  301.                     // redirect to edit mode
  302.                     return $this->redirectTo($existingObject); 
  303.                 }
  304.                 $realStatePercent = $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:realStatePercent')->findBy(['product' => $submittedObject]);
  305.                 $rpLastExtraLeads = [];
  306.                 /** @var $rp realStatePercent */
  307.                 foreach ($realStatePercent as $rp) {
  308.                     $rpLastExtraLeads[$rp->getRealEstate()->getId()] = $rp->getExtraLeads();
  309.                 }
  310.                 //Clean corretores selecionados para atualizar
  311.                 $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:Product')->cleanProductUser($submittedObject->getId());
  312.                 
  313.                 $productUserList = $submittedObject->getProductUsers();
  314.                 //Atualizar corretores selecionados
  315.                 
  316.                 $submittedObject->setProductUsers(null);
  317.                 if($productUserList){
  318.                     $i=0;
  319.                     $em = $this->getDoctrine()->getManager();
  320.                     // Busca em lote em vez de 2 consultas por corretor no loop (mesma
  321.                     // otimizacao de saveLogs() acima). $productUserList pode ser uma
  322.                     // Collection do Doctrine, nao um array puro -- por isso o foreach
  323.                     // em vez de array_map/array_column.
  324.                     $userImobsParsed = [];
  325.                     foreach ($productUserList as $user) {
  326.                         $userImobsParsed[] = explode(':', $user);
  327.                     }
  328.                     $realEstatesById = [];
  329.                     foreach ($this->getDoctrine()->getRepository('ApplicationInternitRealEstateBundle:RealEstate')
  330.                         ->findBy(['id' => array_unique(array_column($userImobsParsed, 0))]) as $re) {
  331.                         $realEstatesById[$re->getId()] = $re;
  332.                     }
  333.                     $corretoresById = [];
  334.                     foreach ($this->getDoctrine()->getRepository('ApplicationSonataUserBundle:User')
  335.                         ->findBy(['id' => array_unique(array_column($userImobsParsed, 1))]) as $u) {
  336.                         $corretoresById[$u->getId()] = $u;
  337.                     }
  338.                     foreach ($userImobsParsed as $userImob) {
  339.                         $corretor = $corretoresById[$userImob[1]] ?? null;
  340.                         $realEstate = $realEstatesById[$userImob[0]] ?? null;
  341.                         if($corretor && $realEstate){
  342.                             $productUser = new ProductUser();
  343.                             $productUser->setUser($corretor);
  344.                             $productUser->setRealEstate($realEstate);
  345.                             $productUser->setProduct($submittedObject);
  346.                             $productUser->setPosition($i);
  347.                             // persist() sem flush() a cada iteracao -- $this->admin->create()
  348.                             // fazia um flush() (uma transacao/UPDATE completa) por corretor, o
  349.                             // que travava com "Lock wait timeout" em produtos com muitos corretores.
  350.                             $em->persist($productUser);
  351.                             $submittedObject->addProductUsers($productUser);
  352.                             $i++;
  353.                         }
  354.                     }
  355.                     // Um unico flush para todos os ProductUser criados neste loop.
  356.                     $em->flush();
  357.                 }
  358.                 $lastRealStatePercent = $this->getDoctrine()->getRepository(realStatePercent::class)->findBy(['product' => $id]);
  359.                 $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:Product')->cleanRealEstatePercent($submittedObject->getId());
  360.                 // Salvar historico das turnos das imobiliarias do produto atual
  361.                 // Quando for criar as novas realState_percent manter o campo turn
  362.                 //Atualizar porcentagem das imobiliarias nas campanhas
  363.                 if($realStatePercentList)
  364.                 {
  365.                     foreach ($realStatePercentList as $imob => $rsPercent) {
  366.                         $imobComEspaco = str_replace(
  367.                             array('_'),
  368.                             ' ',
  369.                             $imob
  370.                         );
  371.                         $realEstate = $this->getDoctrine()->getRepository('ApplicationInternitRealEstateBundle:RealEstate')->findOneByName($imobComEspaco);
  372.                         if($realEstate){
  373.                             /**
  374.                              * @var $lastRP realStatePercent
  375.                              */
  376.                             foreach ($lastRealStatePercent as $lastRP){
  377.                                 if($lastRP->getRealEstate() === $realEstate){
  378.                                     $rsPercent->setTurn($lastRP->getTurn());
  379.                                 }
  380.                             }
  381.                             $rsPercent->setProduct($submittedObject);
  382.                             $rsPercent->setRealEstate($realEstate);
  383.                             $rsPercent->setExtraLeads($rpLastExtraLeads[$realEstate->getId()]?? 0);
  384.                             $newRealStatePercent = $this->admin->create($rsPercent);
  385.                             $submittedObject->addRealStatePercents($newRealStatePercent);
  386.                         }
  387.                     }
  388.                 }
  389.                 $existingObject = $this->admin->update($submittedObject);
  390.                 $this->get('session')->getFlashBag()->set('flash_create_success', 'Mensagem enviada com sucesso');
  391.                 // redirect to edit mode
  392.                 return $this->redirectTo($existingObject);
  393.             } catch (ModelManagerException $e) {
  394.                 $this->handleModelManagerException($e);
  395.                 $isFormValid = false;
  396.             } catch (LockException $e) {
  397.                 $this->get('session')->getFlashBag()->set('flash_create_error', 'Mensagem enviada com sucesso');
  398.             }
  399.             //}
  400.             // show an error message if the form failed validation
  401.             if (!$isFormValid) {
  402.                 if (!$this->isXmlHttpRequest()) {
  403.                     $this->addFlash(
  404.                         'sonata_flash_error',
  405.                         $this->trans(
  406.                             'flash_edit_error',
  407.                             ['%name%' => $this->escapeHtml($this->admin->toString($existingObject))],
  408.                             'SonataAdminBundle'
  409.                         )
  410.                     );
  411.                 }
  412.             } elseif ($this->isPreviewRequested()) {
  413.                 // enable the preview template if the form was valid and preview was requested
  414.                 $templateKey = 'preview';
  415.                 $this->admin->getShow();
  416.             }
  417.        }
  418.        $formView = $form->createView();
  419.         // previewProximoCorretor() e somente-leitura: nao gira o rodizio nem abre
  420.         // transacao, ao contrario de next(). Chamar next() aqui (so pra exibir uma
  421.         // previa) girava o rodizio e prendia lock a cada carregamento da tela --
  422.         // travava ao salvar produtos com muitos leads.
  423.         $broker = $this->get('tupi.caster.service')->previewProximoCorretor($existingObject)
  424.             ?? ['imob' => '— imobiliária sem corretor —'];
  425.        return $this->renderWithExtraParams($this->base."edit.html.twig", [
  426.            'action' => 'edit',
  427.            'form'   => $formView,
  428.            'obj'    => $existingObject,
  429.            'next' => $broker,
  430.        ], null);
  431.     }
  432.     public function showAction($id = null)
  433.     {     
  434.         if (!$this->get('security.token_storage')->getToken()->getUser()->hasRole($this->showActionRoles)) 
  435.         {
  436.             return $this->renderWithExtraParams("@ApplicationInternit/ContentBundle/Resources/views/permission.html.twig");    
  437.         }
  438.         $request = $this->getRequest();
  439.         $id = $request->get($this->admin->getIdParameter());   
  440.         $filter=[
  441.             'from' => '',
  442.             'to' => '',
  443.             'imob' => '',
  444.             'group' => '',
  445.             'user' => '',
  446.         ];
  447.         if(isset($_POST['filter']))
  448.         {
  449.             $filter = $_POST['filter'];
  450.         }   
  451.         $data = $this->getDoctrine()->getRepository($this->bundle)->find($id);
  452.         $template = $this->base.'show.html.twig';
  453.         //$imobFilter = $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:Lead')->findAllImobs($id);
  454.         $imobs = $this->getDoctrine()->getRepository(RealEstate::class)->findAll();
  455.         foreach ($imobs as $imob){
  456.             $imobFilter[] = [ 'name' => $imob->getName() ];
  457.         }
  458.         $users = $this->getDoctrine()->getRepository(User::class)->findAll();
  459.         foreach ($users as $user){
  460.             $userFilter[] = [ 'name' => $user->getFirstname() ];
  461.         }
  462.        // dd($imobFilter);
  463.         $userGroup = $this->get('security.token_storage')->getToken()->getUser()->getGroups()[0]->getName();
  464.         return $this->renderWithExtraParams($template, [
  465.             'action' => 'show',
  466.             'data' => $data,
  467.             'imobFilter' => $imobFilter,
  468.             'userFilter' => $userFilter,
  469.             'filter' => $filter,
  470.             'userGroup' => $userGroup,
  471.         ], null);
  472.         return parent::showAction($id = null);
  473.     }
  474.     function exportLogSendedAction()
  475.     {
  476.         $request = $this->getRequest();
  477.         $id = $request->get($this->admin->getIdParameter());          
  478.         return $this->exportLogs($id, "DISTRIBUICAO");        
  479.     }
  480.     public function exportLogAction()
  481.     {
  482.         $request = $this->getRequest();
  483.         $id = $request->get($this->admin->getIdParameter());          
  484.         return $this->exportLogs($id, "CAMPANHA");      
  485.     }
  486.     public function exportLogs($id = null, $type = null)
  487.     {
  488.         $request = $this->getRequest();
  489.         $id = $request->get($this->admin->getIdParameter());          
  490.         $logEntities = $this->getDoctrine()->getRepository("ApplicationInternitLeadBundle:ProductLog")->findBy(['product' => $id, 'type' => $type]);
  491.         // dump($logEntities); exit;
  492.         if (!$logEntities) {
  493.             return  $response = new Response("Log com ID {$id} não encontrado.");
  494.             //throw $this->createNotFoundException("Log com ID {$id} não encontrado.");
  495.         }
  496.         $allLogs = [];
  497.         $allLogs = [
  498.                 'id' => $logEntities[0]->getId(),
  499.                 'createdAt' => $logEntities[0]->getCreatedAt()->format('Y-m-d H:i:s'),
  500.                 'product' => $logEntities[0]->getProduct() ? $logEntities[0]->getProduct()->getName() : null,
  501.                 
  502.             ];
  503.         $realEstateArray = [];
  504.         foreach ($logEntities as $logEntity) {
  505.             $logData = json_decode($logEntity->getLog(), true);
  506.             $realEstateArray[] = $logData;
  507.             // Adiciona metadados opcionais, como ID ou data
  508.             
  509.         }
  510.         $allLogs['data'] = $realEstateArray;
  511.         
  512.         $jsonContent = json_encode($allLogs, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
  513.         $fileName = 'logs_' . date('Y-m-d_H-i-s') . '.json';
  514.         $response = new Response($jsonContent);
  515.         $response->headers->set('Content-Type', 'application/json');
  516.         $response->headers->set('Content-Disposition', $response->headers->makeDisposition(
  517.             ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  518.             $fileName
  519.         ));
  520.         return $response;
  521.            
  522.     }
  523.     /**
  524.      * Trata a requisição para exportar os leads filtrados em um arquivo csv.
  525.      * @param int $id - ID da campanha cujos leads serão exportados.
  526.      */
  527.     public function exportFilteredAction($id = null)
  528.     {
  529.         if (!$this->get('security.token_storage')->getToken()->getUser()->hasRole($this->exportFilteredActionRoles)) 
  530.         {
  531.             return $this->renderWithExtraParams("@ApplicationInternit/ContentBundle/Resources/views/permission.html.twig");    
  532.         }
  533.         $request = $this->getRequest();
  534.         $id = $request->get($this->admin->getIdParameter());
  535.         $product = $this->getDoctrine()->getRepository($this->bundle)->find($id);
  536.         $productName = is_null($product) ? '' : $product->getName();
  537.         $filter = $_POST['filter'];
  538.         $leads = $this->getDoctrine()->getRepository('ApplicationInternitLeadBundle:Lead')
  539.             ->findLeadByGroup($id, $filter['group'], $filter);
  540.         $data = [];
  541.         if($filter['user'])
  542.         {
  543.             $user = $this->getDoctrine()->getRepository(User::class)->findOneBy(['firstname' => $filter['user']]);
  544.             $data = [];
  545.             foreach ($leads as $lead)
  546.                 if($lead['brokerEmail'] == $user->getEmail())
  547.                     $data[] = $lead;
  548.             $leads = $data;
  549.         }
  550.         $spreadsheet = new Spreadsheet();
  551.         /* @var $sheet \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet */
  552.         $sheet = $spreadsheet->getActiveSheet();
  553.         $date = date('d/m/Y H:i:s');
  554.         $dateFileName = date('d-m-y__H-i-s');
  555.         $this->generateFileContent($sheet, $leads);
  556.         
  557.         $writer = new Csv($spreadsheet);
  558.         $group = empty($filter['group']) ? '' : $filter['group'];
  559.         $fileName = "leads_{$productName}_{$group}_$dateFileName.csv";
  560.         $contentType = 'text/csv';
  561.         return $this->generateFileResponse($fileName, $contentType, $writer);
  562.     }
  563.     /**
  564.      * Escreve os leads em um arquivo de spreadsheet.
  565.      * 
  566.      * @param \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Worksheet $sheet - planilha de trabalho atual
  567.      * @param array $leads - array dos leads filtrados para escrita.
  568.      */
  569.     private function generateFileContent($sheet, $leads)
  570.     {
  571.         $columns = [
  572.             'A' => ['label' => 'Nome', 'field' => 'name'],
  573.             'B' => ['label' => 'E-mail', 'field' => 'email'],
  574.             'C' => ['label' => 'Telefone', 'field' => 'phone'],
  575.             'D' => ['label' => 'Imobiliaria', 'field' => 'brokerRealState'],
  576.             'E' => ['label' => 'E-mail corretor', 'field' => 'brokerEmail'],
  577.             'F' => ['label' => 'Fidelidade', 'field' => 'loyalty'],
  578.             'G' => ['label' => 'Origem', 'field' => 'origem'],
  579.             'H' => ['label' => 'Grupo', 'field' => 'group'],
  580.             'I' => ['label' => 'Data de envio', 'field' => 'createdAt'],
  581.             'J' => ['label' => 'Enviado', 'field' => 'send_status'],
  582.             'K' => ['label' => 'Utm Source', 'field' => 'utm_source'],
  583.             'L' => ['label' => 'Utm Medium', 'field' => 'utm_medium'],
  584.             'M' => ['label' => 'Utm Campaign', 'field' => 'utm_campaign'],
  585.             
  586.         ];
  587.         $indRow = 1;
  588.         foreach($columns as $col => $content) {
  589.             $sheet->setCellValue($col . $indRow, $content['label']);
  590.         }
  591.         $indRow = 2;
  592.         foreach($leads as $lead) {
  593.             foreach ($columns as $col => $content) {
  594.                 $field = $content['field'];
  595.                 $sheet->setCellValue($col . $indRow, $lead[$field]);
  596.             }
  597.             $indRow++;
  598.         }
  599.     }
  600.     /**
  601.      * Gera o arquivo csv exportado como uma resposta para o cliente.
  602.      * 
  603.      * @param string $fileName - nome do arquivo
  604.      * @param string $contentType - tipo mime do arquivo
  605.      * @param use PhpOffice\PhpSpreadsheet\Writer\Csv $writer - objeto que vai exportar o arquivo csv 
  606.      * @return StreamedResponse
  607.      */
  608.     private function generateFileResponse($fileName, $contentType, $writer)
  609.     {
  610.         $response = new StreamedResponse();
  611.         $response->headers->set('Content-Type', $contentType);
  612.         $response->headers->set('Content-Disposition', 'attachment;filename="'.$fileName.'"');
  613.         $response->setPrivate();
  614.         $response->headers->addCacheControlDirective('no-cache', true);
  615.         $response->headers->addCacheControlDirective('must-revalidate', true);
  616.         $response->setCallback(function() use ($writer) {
  617.             $writer->save('php://output');
  618.         });
  619.         return $response;
  620.     }
  621.     public function getBundleName()
  622.     {
  623.         return 'ApplicationInternitLeadBundle';
  624.     }
  625.     public function getEntityName()
  626.     {
  627.         return 'Product';
  628.     }
  629.     public function getFormType()
  630.     {
  631.         return 'App\Application\Internit\LeadBundle\Form\ProductType';
  632.     }
  633. }