vendor/uvdesk/support-center-bundle/Controller/Website.php line 165

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\SupportCenterBundle\Controller;
  3. use Doctrine\Common\Collections\Criteria;
  4. use Webkul\UVDesk\SupportCenterBundle\Form;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Symfony\Component\HttpFoundation\ParameterBag;
  8. use Webkul\UVDesk\SupportCenterBundle\Entity\Article;
  9. use Webkul\UVDesk\SupportCenterBundle\Entity\Solutions;
  10. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  11. use Webkul\UVDesk\SupportCenterBundle\Entity\ArticleViewLog;
  12. use Webkul\UVDesk\SupportCenterBundle\Entity\SolutionCategory;
  13. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  14. use Webkul\UVDesk\SupportCenterBundle\Entity\KnowledgebaseWebsite;
  15. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Website as CoreWebsite;
  16. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  17. use Symfony\Component\Security\Core\Security;
  18. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  19. use Doctrine\ORM\EntityManagerInterface;
  20. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  21. use Webkul\UVDesk\CoreFrameworkBundle\Entity\UserInstance;
  22. use Symfony\Component\HttpFoundation\RequestStack;
  23. use Symfony\Component\EventDispatcher\GenericEvent;
  24. use Symfony\Component\DependencyInjection\ContainerInterface;
  25. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. use Symfony\Component\HttpFoundation\JsonResponse;
  28. class Website extends Controller
  29. {
  30.     private $visibility = ['public'];
  31.     private $limit 5;
  32.     private $company;
  33.     private function isKnowledgebaseActive()
  34.     {
  35.         $entityManager $this->getDoctrine()->getManager();
  36.         $website $entityManager->getRepository(CoreWebsite::class)->findOneByCode('knowledgebase');
  37.         if (!empty($website)) {
  38.             $knowledgebaseWebsite $entityManager->getRepository(KnowledgebaseWebsite::class)->findOneBy(['website' => $website->getId(), 'status' => true]);
  39.             if (!empty($knowledgebaseWebsite) && true == $knowledgebaseWebsite->getIsActive()) {
  40.                 return true;
  41.             }
  42.         }
  43.         throw new NotFoundHttpException('Page Not Found');
  44.     }
  45.     public function home(Request $request)
  46.     {
  47.         $user=$this->get('user.service')->getSessionUser();
  48.         if(!$user){
  49.            return new Response($this->container->get('twig')->render('@UVDeskSupportCenter//Knowledgebase//login.html.twig', [
  50.             ]));
  51.         }
  52.         
  53.         $this->isKnowledgebaseActive();
  54.         // Usar vista moderna unificada por defecto (puedes cambiar 'classic' para usar la vieja)
  55.         if ($request->query->get('view') != 'classic') {
  56.             return $this->modernUnifiedView($request);
  57.         }
  58.         $parameterBag = [
  59.             'visibility' => 'public',
  60.             'sort' => 'id',
  61.             'direction' => 'desc'
  62.         ];
  63.         $articleRepository $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Article');
  64.         $solutionRepository $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Solutions');
  65.         $twigResponse = [
  66.             'searchDisable' => false,
  67.             'popArticles' => $articleRepository->getPopularTranslatedArticles($request->getLocale()),
  68.             'solutions' => $solutionRepository->getAllSolutions(new ParameterBag($parameterBag), $this->container'a', [1]),
  69.         ];
  70.         $newResult = [];
  71.        
  72.         foreach ($twigResponse['solutions'] as $key => $result) {
  73.             $newResult[] = [
  74.                 'id' => $result->getId(),
  75.                 'name' => $result->getName(),
  76.                 'description' => $result->getDescription(),
  77.                 'visibility' => $result->getVisibility(),
  78.                 'solutionImage' => ($result->getSolutionImage() == null) ? '' $result->getSolutionImage(),
  79.                 'categoriesCount' => $solutionRepository->getCategoriesCountBySolution($result->getId()),
  80.                 'categories' => $solutionRepository->getCategoriesWithCountBySolution($result->getId()),
  81.                 'articleCount' => $solutionRepository->getArticlesCountBySolution($result->getId()),
  82.             ];
  83.         }
  84.         $twigResponse['solutions']['results'] = $newResult;
  85.         $twigResponse['solutions']['categories'] = array_map(function($category) use ($articleRepository) {
  86.             $parameterBag = [
  87.                 'categoryId' => $category['id'],
  88.                 'status' => 1,
  89.                 'sort' => 'id',
  90.                 'limit'=>10,
  91.                 'direction' => 'desc'
  92.             ];
  93.             $article =  $articleRepository->getAllArticles(new ParameterBag($parameterBag), $this->container'a.id, a.name, a.slug, a.stared');
  94.              
  95.             return [
  96.                 'id' => $category['id'],
  97.                 'name' => $category['name'],
  98.                 'description' => $category['description'],
  99.                 'articles' => $article
  100.             ];
  101.         }, $solutionRepository->getAllCategories(102));
  102.         
  103.         $filterArray = ['id' => 5];
  104.         $solution $this->getDoctrine()
  105.             ->getRepository('UVDeskSupportCenterBundle:Solutions')
  106.             ->findOneBy($filterArray);
  107.         $parameterBag = [
  108.             'solutionId' => $solution->getId(),
  109.             'status' => 1,
  110.             'sort' => 'id',
  111.             'direction' => 'desc'
  112.         ];
  113.         $articles $this->getDoctrine()
  114.             ->getRepository('UVDeskSupportCenterBundle:Article')
  115.             ->getAllArticles(new ParameterBag($parameterBag), $this->container'a.id, a.name, a.slug, a.stared');
  116.         $twigResponse['articles'] = array_reverse($articles);
  117.         return $this->render('@UVDeskSupportCenter//Knowledgebase//index.html.twig'$twigResponse);
  118.     }
  119.     /**
  120.      * Vista moderna unificada con navegación tipo Ajax Systems
  121.      */
  122.     public function modernUnifiedView(Request $request)
  123.     {
  124.         $em $this->getDoctrine()->getManager();
  125.         $articleRepository $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Article');
  126.         $solutionRepository $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Solutions');
  127.         
  128.         // Obtener TODAS las soluciones activas con visibilidad pública
  129.         $parameterBag = [
  130.             'visibility' => 'public',
  131.             'sort' => 'id',
  132.             'direction' => 'asc'
  133.         ];
  134.         $solutions $solutionRepository->getAllSolutions(new ParameterBag($parameterBag), $this->container'a', [1]);
  135.         
  136.         // Obtener TODOS los artículos activos directamente de la base de datos
  137.         $qb $em->createQueryBuilder();
  138.         $qb->select('a')
  139.            ->from('UVDeskSupportCenterBundle:Article''a')
  140.            ->where('a.status = :status')
  141.            ->setParameter('status'1)
  142.            ->orderBy('a.id''ASC');
  143.         
  144.         $allArticles $qb->getQuery()->getResult();
  145.         
  146.         error_log('Total articles found in database: ' count($allArticles));
  147.         
  148.         $completeStructure = [];
  149.         
  150.         foreach ($solutions as $solution) {
  151.             error_log('Processing solution: ' $solution->getId() . ' - ' $solution->getName());
  152.             
  153.             $categoriesData $solutionRepository->getCategoriesWithCountBySolution($solution->getId());
  154.             $categories = [];
  155.             
  156.             $allCategorizedArticleIds = [];
  157.             $solutionArticleIds = [];
  158.             
  159.             // Obtener artículos de esta solución a través de las categorías
  160.             // Solution → SolutionCategoryMapping → Category → ArticleCategory → Article
  161.             $qb2 $em->createQueryBuilder();
  162.             $qb2->select('DISTINCT a')
  163.                 ->from('UVDeskSupportCenterBundle:Article''a')
  164.                 ->join('UVDeskSupportCenterBundle:ArticleCategory''ac''WITH''a.id = ac.articleId')
  165.                 ->join('UVDeskSupportCenterBundle:SolutionCategoryMapping''scm''WITH''ac.categoryId = scm.categoryId')
  166.                 ->where('a.status = :status')
  167.                 ->andWhere('scm.solutionId = :solutionId')
  168.                 ->setParameter('status'1)
  169.                 ->setParameter('solutionId'$solution->getId())
  170.                 ->orderBy('a.id''ASC');
  171.             
  172.             $solutionArticles $qb2->getQuery()->getResult();
  173.             
  174.             foreach ($solutionArticles as $article) {
  175.                 $articleId $article->getId();
  176.                 $solutionArticleIds[] = $articleId;
  177.             }
  178.             
  179.             error_log('Solution ' $solution->getId() . ' has ' count($solutionArticles) . ' articles');
  180.             
  181.             // Procesar categorías
  182.             foreach ($categoriesData as $categoryData) {
  183.                 $qb3 $em->createQueryBuilder();
  184.                 $qb3->select('a')
  185.                     ->from('UVDeskSupportCenterBundle:Article''a')
  186.                     ->join('UVDeskSupportCenterBundle:ArticleCategory''ac''WITH''a.id = ac.articleId')
  187.                     ->where('a.status = :status')
  188.                     ->andWhere('ac.categoryId = :categoryId')
  189.                     ->setParameter('status'1)
  190.                     ->setParameter('categoryId'$categoryData['id'])
  191.                     ->orderBy('a.id''ASC');
  192.                 
  193.                 $categoryArticles $qb3->getQuery()->getResult();
  194.                 
  195.                 // Formatear artículos para el template
  196.                 $formattedArticles = [];
  197.                 foreach ($categoryArticles as $article) {
  198.                     $allCategorizedArticleIds[] = $article->getId();
  199.                     $dateAdded $article->getDateAdded();
  200.                     $dateAddedFormatted '';
  201.                     if ($dateAdded instanceof \DateTime) {
  202.                         $dateAddedFormatted $dateAdded->format('d/m/Y');
  203.                     }
  204.                     $formattedArticles[] = [
  205.                         'id' => $article->getId(),
  206.                         'name' => $article->getName(),
  207.                         'slug' => $article->getSlug(),
  208.                         'stared' => $article->getStared(),
  209.                         'content' => $article->getContent(),
  210.                         'dateAdded' => $dateAddedFormatted
  211.                     ];
  212.                 }
  213.                 
  214.                 error_log('Category ' $categoryData['id'] . ' (' $categoryData['name'] . ') has ' count($formattedArticles) . ' articles');
  215.                 
  216.                 $categories[] = [
  217.                     'id' => $categoryData['id'],
  218.                     'name' => $categoryData['name'],
  219.                     'description' => $categoryData['description'] ?? '',
  220.                     'articleCount' => count($formattedArticles),
  221.                     'articles' => $formattedArticles
  222.                 ];
  223.             }
  224.             
  225.             // Obtener artículos directos (sin categoría) de esta solución
  226.             $directArticles = [];
  227.             foreach ($solutionArticles as $article) {
  228.                 $articleId $article->getId();
  229.                 // Si no está en ninguna categoría y pertenece a esta solución
  230.                 if (!in_array($articleId$allCategorizedArticleIds)) {
  231.                     $dateAdded $article->getDateAdded();
  232.                     $dateAddedFormatted '';
  233.                     if ($dateAdded instanceof \DateTime) {
  234.                         $dateAddedFormatted $dateAdded->format('d/m/Y');
  235.                     }
  236.                     $directArticles[] = [
  237.                         'id' => $article->getId(),
  238.                         'name' => $article->getName(),
  239.                         'slug' => $article->getSlug(),
  240.                         'stared' => $article->getStared(),
  241.                         'content' => $article->getContent(),
  242.                         'dateAdded' => $dateAddedFormatted
  243.                     ];
  244.                 }
  245.             }
  246.             
  247.             error_log('Solution ' $solution->getId() . ' has ' count($directArticles) . ' direct articles');
  248.             
  249.             $completeStructure[] = [
  250.                 'id' => $solution->getId(),
  251.                 'name' => $solution->getName(),
  252.                 'description' => $solution->getDescription(),
  253.                 'solutionImage' => $solution->getSolutionImage(),
  254.                 'categories' => $categories,
  255.                 'directArticles' => $directArticles,
  256.                 'totalArticles' => count($solutionArticles)
  257.             ];
  258.         }
  259.         
  260.         // Si se solicita un artículo específico
  261.         $selectedArticle null;
  262.         $articleSlug $request->query->get('article');
  263.         
  264.         if ($articleSlug) {
  265.             $article $articleRepository->findOneBy(['status' => 1'slug' => $articleSlug]);
  266.             if ($article) {
  267.                 $selectedArticle = [
  268.                     'id' => $article->getId(),
  269.                     'name' => $article->getName(),
  270.                     'content' => $article->getContent(),
  271.                     'slug' => $article->getSlug(),
  272.                     'dateAdded' => $this->get('user.service')->convertToTimezone($article->getDateAdded()),
  273.                     'articleAuthor' => $articleRepository->getArticleAuthorDetails($article->getId()),
  274.                 ];
  275.             }
  276.         }
  277.         
  278.         // Obtener artículos para el header (similar a la vista original)
  279.         $filterArray = ['id' => 5];
  280.         $solutionForArticles $this->getDoctrine()
  281.             ->getRepository('UVDeskSupportCenterBundle:Solutions')
  282.             ->findOneBy($filterArray);
  283.         
  284.         $articles = [];
  285.         if ($solutionForArticles) {
  286.             $parameterBag = [
  287.                 'solutionId' => $solutionForArticles->getId(),
  288.                 'status' => 1,
  289.                 'sort' => 'id',
  290.                 'direction' => 'desc'
  291.             ];
  292.             
  293.             $articles $this->getDoctrine()
  294.                 ->getRepository('UVDeskSupportCenterBundle:Article')
  295.                 ->getAllArticles(new ParameterBag($parameterBag), $this->container'a.id, a.name, a.slug, a.stared');
  296.             
  297.             $articles array_reverse($articles);
  298.         }
  299.         
  300.         // Debug: Log structure count
  301.         error_log('Total solutions (folders) found: ' count($completeStructure));
  302.         foreach ($completeStructure as $folder) {
  303.             error_log('Folder: ' $folder['name'] . ' - Categories: ' count($folder['categories']) . ' - Direct Articles: ' count($folder['directArticles']));
  304.         }
  305.         
  306.         return $this->render('@UVDeskSupportCenter/Knowledgebase/modern-unified.html.twig', [
  307.             'structure' => $completeStructure,
  308.             'selectedArticle' => $selectedArticle,
  309.             'searchDisable' => false,
  310.             'articles' => $articles// Para el header
  311.         ]);
  312.     }
  313.     /**
  314.      * Cargar artículo vía AJAX para la vista moderna
  315.      */
  316.     public function loadArticleAjax(Request $request)
  317.     {
  318.         $this->isKnowledgebaseActive();
  319.         
  320.         $articleSlug $request->query->get('slug');
  321.         if (!$articleSlug) {
  322.             return new JsonResponse(['error' => 'Article slug required'], 400);
  323.         }
  324.         
  325.         $articleRepository $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Article');
  326.         $article $articleRepository->findOneBy(['status' => 1'slug' => $articleSlug]);
  327.         
  328.         if (!$article) {
  329.             return new JsonResponse(['error' => 'Article not found'], 404);
  330.         }
  331.         
  332.         $articleAuthor $articleRepository->getArticleAuthorDetails($article->getId());
  333.         
  334.         // Formatear fecha correctamente
  335.         $dateAdded $article->getDateAdded();
  336.         $dateAddedFormatted '';
  337.         if ($dateAdded) {
  338.             if ($dateAdded instanceof \DateTime) {
  339.                 $dateAddedFormatted $dateAdded->format('d/m/Y');
  340.             } else {
  341.                 // Si es string, intentar convertirlo
  342.                 try {
  343.                     $dateObj = new \DateTime($dateAdded);
  344.                     $dateAddedFormatted $dateObj->format('d/m/Y');
  345.                 } catch (\Exception $e) {
  346.                     $dateAddedFormatted '';
  347.                 }
  348.             }
  349.         }
  350.         
  351.         return new JsonResponse([
  352.             'id' => $article->getId(),
  353.             'name' => $article->getName(),
  354.             'content' => $article->getContent(),
  355.             'slug' => $article->getSlug(),
  356.             'dateAdded' => $dateAddedFormatted,
  357.             'author' => $articleAuthor ? [
  358.                 'firstName' => $articleAuthor->firstName ?? '',
  359.                 'lastName' => $articleAuthor->lastName ?? '',
  360.             ] : null,
  361.         ]);
  362.     }
  363.     public function listCategories(Request $request)
  364.     {
  365.         $this->isKnowledgebaseActive();
  366.         $solutionRepository $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Solutions');
  367.         $categoryCollection $solutionRepository->getAllCategories(104);
  368.         
  369.         return $this->render('@UVDeskSupportCenter/Knowledgebase/categoryListing.html.twig', [
  370.             'categories' => $categoryCollection,
  371.             'categoryCount' => count($categoryCollection),
  372.         ]);
  373.     }
  374.     public function changePass($email,$pass)
  375.     {   
  376.         try{
  377.             $entityManager $this->getDoctrine()->getManager();
  378.             $user $entityManager->getRepository('UVDeskCoreFrameworkBundle:User')->findOneByEmail($email) ?: new User();
  379.             $encodedPassword $this->container->get('security.password_encoder')->encodePassword($user$pass);
  380.             $user->setPassword($encodedPassword);
  381.             $entityManager->persist($user);
  382.             $entityManager->flush();
  383.             return $this->render('@UVDeskSupportCenter/Knowledgebase/json.html.twig', ['return'=>'ok']);
  384.         }catch(Exception $e){
  385.             return $this->render('@UVDeskSupportCenter/Knowledgebase/json.html.twig', ['return'=>$es]);
  386.         }
  387.     }
  388.     public function viewFolder(Request $request)
  389.     {
  390.         //////////////
  391.         //colocar sesion
  392.         /////////////
  393.         
  394.         $this->isKnowledgebaseActive();
  395.         
  396.         if(!$request->attributes->get('solution'))
  397.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  398.         $filterArray = ['id' => $request->attributes->get('solution')];
  399.         $solution $this->getDoctrine()
  400.                     ->getRepository('UVDeskSupportCenterBundle:Solutions')
  401.                     ->findOneBy($filterArray);
  402.         if(!$solution)
  403.             $this->noResultFound();
  404.         $sesion=null;
  405.         if($this->get('user.service')->getSessionUser()!=null)
  406.             $sesion=true;
  407.         $breadcrumbs = [
  408.             [
  409.                 'label' => $this->get('translator')->trans('Support Center'),
  410.                 'url' => $this->generateUrl('helpdesk_knowledgebase'),
  411.                   'sesion'=> $sesion
  412.             ],
  413.             [
  414.                 'label' => $solution->getName(),
  415.                 'url' => '#',
  416.                   'sesion'=> $sesion
  417.             ],
  418.         ];
  419.         $testArray = [1234];
  420.         foreach ($testArray as $test) {
  421.             $categories[] = [
  422.                 'id' => $test,
  423.                 'name' => $test " name",
  424.                 'articleCount' => $test " articleCount",
  425.             ];
  426.         }
  427.         return $this->render('@UVDeskSupportCenter//Knowledgebase//folder.html.twig', [
  428.             'folder' => $solution,
  429.             'categoryCount' => $this->getDoctrine()
  430.                 ->getRepository('UVDeskSupportCenterBundle:Solutions')
  431.                 ->getCategoriesCountBySolution($solution->getId()),
  432.             'categories' => $this->getDoctrine()
  433.                 ->getRepository('UVDeskSupportCenterBundle:Solutions')
  434.                 ->getCategoriesWithCountBySolution($solution->getId()),
  435.             'breadcrumbs' => $breadcrumbs
  436.         ]);
  437.     }
  438. //////////aca////
  439.     public function viewFolderArticle(Request $request)
  440.     {
  441.         $this->isKnowledgebaseActive();
  442.         if(!$request->attributes->get('solution'))
  443.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  444.         $filterArray = ['id' => $request->attributes->get('solution')];
  445.         $solution $this->getDoctrine()
  446.                     ->getRepository('UVDeskSupportCenterBundle:Solutions')
  447.                     ->findOneBy($filterArray);
  448.         if(!$solution)
  449.             $this->noResultFound();
  450.         $sesion=null;
  451.         if($this->get('user.service')->getSessionUser()!=null)
  452.             $sesion=true;
  453.         $breadcrumbs = [
  454.             [
  455.                 'label' => $this->get('translator')->trans('Support Center'),
  456.                 'url' => $this->generateUrl('helpdesk_knowledgebase'),
  457.                 'sesion'=>$sesion
  458.             ],
  459.             [
  460.                 'label' => $solution->getName(),
  461.                 'url' => '#',
  462.                  'sesion'=>$sesion
  463.             ],
  464.         ];
  465.         $parameterBag = [
  466.             'solutionId' => $solution->getId(),
  467.             'status' => 1,
  468.             'sort' => 'id',
  469.             'direction' => 'desc'
  470.         ];
  471.         $article_data = [
  472.             'folder' => $solution,
  473.             'articlesCount' => $this->getDoctrine()
  474.                 ->getRepository('UVDeskSupportCenterBundle:Solutions')
  475.                 ->getArticlesCountBySolution($solution->getId(), [1]),
  476.             'articles' => $this->getDoctrine()
  477.                 ->getRepository('UVDeskSupportCenterBundle:Article')
  478.                 ->getAllArticles(new ParameterBag($parameterBag), $this->container'a.id, a.name, a.slug, a.stared'),
  479.             'breadcrumbs' => $breadcrumbs,
  480.         ];
  481.         return $this->render('@UVDeskSupportCenter/Knowledgebase/folderArticle.html.twig'$article_data);
  482.     }
  483.     public function viewCategory(Request $request)
  484.     {
  485.         $this->isKnowledgebaseActive();
  486.         if(!$request->attributes->get('category'))
  487.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  488.         $filterArray = array(
  489.                             'id' => $request->attributes->get('category'),
  490.                             'status' => 1,
  491.                         );
  492.        
  493.         $category $this->getDoctrine()
  494.                     ->getRepository('UVDeskSupportCenterBundle:SolutionCategory')
  495.                     ->findOneBy($filterArray);
  496.     
  497.         if(!$category)
  498.             $this->noResultFound();
  499.           $sesion=null;
  500.         if($this->get('user.service')->getSessionUser()!=null)
  501.             $sesion=true;
  502.         
  503.         $breadcrumbs = [
  504.             [ 'label' => $this->get('translator')->trans('Support Center'),'url' => $this->generateUrl('helpdesk_knowledgebase'),'sesion'=>$sesion ],
  505.             [ 'label' => $category->getName(),'url' => '#','sesion'=>$sesion ],
  506.         ];
  507.         
  508.         $parameterBag = [
  509.             'categoryId' => $category->getId(),
  510.             'status' => 1,
  511.             'sort' => 'id',
  512.             'direction' => 'desc'
  513.         ];
  514.         $category_data=  array(
  515.             'category' => $category,
  516.             'articlesCount' => $this->getDoctrine()
  517.                             ->getRepository('UVDeskSupportCenterBundle:SolutionCategory')
  518.                             ->getArticlesCountByCategory($category->getId(), [1]),
  519.             'articles' => $this->getDoctrine()
  520.                         ->getRepository('UVDeskSupportCenterBundle:Article')
  521.                         ->getAllArticles(new ParameterBag($parameterBag), $this->container'a.id, a.name, a.slug, a.stared'),
  522.             'breadcrumbs' => $breadcrumbs
  523.         );
  524.         return $this->render('@UVDeskSupportCenter/Knowledgebase/category.html.twig',$category_data);
  525.     }
  526.    
  527.     public function viewArticle(Request $request)
  528.     {
  529.         $this->isKnowledgebaseActive();
  530.        
  531.         if (!$request->attributes->get('article') && !$request->attributes->get('slug')) {
  532.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  533.         }
  534.         $entityManager $this->getDoctrine()->getManager();
  535.         $user $this->get('user.service')->getCurrentUser();
  536.         $articleRepository $entityManager->getRepository('UVDeskSupportCenterBundle:Article');
  537.         if ($request->attributes->get('article')) {
  538.             $article $articleRepository->findOneBy(['status' => 1'id' => $request->attributes->get('article')]);
  539.         } else {
  540.             $article $articleRepository->findOneBy(['status' => 1,'slug' => $request->attributes->get('slug')]);
  541.         }
  542.        
  543.         if (empty($article)) {
  544.             $this->noResultFound();
  545.         }
  546.         $article->setViewed((int) $article->getViewed() + 1);
  547.         
  548.         // Log article view
  549.         $articleViewLog = new ArticleViewLog();
  550.         $articleViewLog->setUser(($user != null && $user != 'anon.') ? $user null);
  551.         
  552.         $articleViewLog->setArticle($article);
  553.         $articleViewLog->setViewedAt(new \DateTime('now'));
  554.         $entityManager->persist($article);
  555.         $entityManager->persist($articleViewLog);
  556.         $entityManager->flush();
  557.         
  558.         // Get article feedbacks
  559.         $feedbacks = ['enabled' => false'submitted' => false'article' => $articleRepository->getArticleFeedbacks($article)];
  560.         if (!empty($user) && $user != 'anon.') {
  561.             $feedbacks['enabled'] = true;
  562.             if (!empty($feedbacks['article']['collection']) && in_array($user->getId(), array_column($feedbacks['article']['collection'], 'user'))) {
  563.                 $feedbacks['submitted'] = true;
  564.             }
  565.         }
  566.           $sesion=null;
  567.         if($this->get('user.service')->getSessionUser()!=null)
  568.             $sesion=true;
  569.         // @TODO: App popular articles
  570.         $article_details = [
  571.             'article' => $article,
  572.             'breadcrumbs' => [
  573.                 ['label' => $this->get('translator')->trans('Support Center'), 'url' => $this->generateUrl('helpdesk_knowledgebase'),'sesion'=>$sesion],
  574.                 ['label' => $article->getName(), 'url' => '#','sesion'=>$sesion]
  575.             ],
  576.             'dateAdded' => $this->get('user.service')->convertToTimezone($article->getDateAdded()),
  577.             'articleTags' => $articleRepository->getTagsByArticle($article->getId()),
  578.             'articleAuthor' => $articleRepository->getArticleAuthorDetails($article->getId()),
  579.             'relatedArticles' => $articleRepository->getAllRelatedyByArticle(['locale' => $request->getLocale(), 'articleId' => $article->getId()], [1]),
  580.             'popArticles'  => $articleRepository->getPopularTranslatedArticles($request->getLocale())
  581.         ];
  582.      
  583.         return $this->render('@UVDeskSupportCenter/Knowledgebase/article.html.twig',$article_details);
  584.     }
  585.     public function searchKnowledgebase(Request $request)
  586.     {
  587.         $this->isKnowledgebaseActive();
  588.         $searchQuery $request->query->get('s');
  589.         if (empty($searchQuery)) {
  590.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  591.         }
  592.         $articleCollection $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Article')->getArticleBySearch($request);
  593.         return $this->render('@UVDeskSupportCenter/Knowledgebase/search.html.twig', [
  594.             'search' => $searchQuery,
  595.             'articles' => $articleCollection,
  596.         ]);
  597.     }
  598.     public function viewTaggedResources(Request $request)
  599.     {
  600.         $this->isKnowledgebaseActive();
  601.         $tagQuery $request->attributes->get('tag');
  602.         if (empty($tagQuery)) {
  603.             return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  604.         }
  605.         $tagLabel $request->attributes->get('name');
  606.         $articleCollection $this->getDoctrine()->getRepository('UVDeskSupportCenterBundle:Article')->getArticleByTags([$tagLabel]);
  607.          $sesion=null;
  608.         if($this->get('user.service')->getSessionUser()!=null)
  609.             $sesion=true;
  610.         return $this->render('@UVDeskSupportCenter/Knowledgebase/search.html.twig', [
  611.             'articles' => $articleCollection,
  612.             'search' => $tagLabel,
  613.             'breadcrumbs' => [
  614.                 ['label' => $this->get('translator')->trans('Support Center'), 'url' => $this->generateUrl('helpdesk_knowledgebase'),'sesion'=>$sesion],
  615.                 ['label' => $tagLabel'url' => '#','sesion'=>$sesion],
  616.             ],
  617.         ]);
  618.     }
  619.     public function rateArticle($articleIdRequest $request)
  620.     {
  621.         $this->isKnowledgebaseActive();
  622.         // @TODO: Refactor
  623.             
  624.         // if ($request->getMethod() != 'POST') {
  625.         //     return $this->redirect($this->generateUrl('helpdesk_knowledgebase'));
  626.         // }
  627.         // $company = $this->getCompany();
  628.         // $user = $this->container->get('user.service')->getCurrentUser();
  629.         $response = ['code' => 404'content' => ['alertClass' => 'danger''alertMessage' => 'An unexpected error occurred. Please try again later.']];
  630.         // if (!empty($user) && $user != 'anon.') {
  631.         //     $entityManager = $this->getDoctrine()->getEntityManager();
  632.         //     $article = $entityManager->getRepository('WebkulSupportCenterBundle:Article')->findOneBy(['id' => $articleId, 'companyId' => $company->getId()]);
  633.         //     if (!empty($article)) {
  634.         //         $providedFeedback = $request->request->get('feedback');
  635.         //         if (!empty($providedFeedback) && in_array(strtolower($providedFeedback), ['positive', 'neagtive'])) {
  636.         //             $isArticleHelpful = ('positive' == strtolower($providedFeedback)) ? true : false;
  637.         //             $articleFeedback = $entityManager->getRepository('WebkulSupportCenterBundle:ArticleFeedback')->findOneBy(['article' => $article, 'ratedCustomer' => $user]);
  638.         //             $response = ['code' => 200, 'content' => ['alertClass' => 'success', 'alertMessage' => 'Feedback saved successfully.']];
  639.         //             if (empty($articleFeedback)) {
  640.         //                 $articleFeedback = new \Webkul\SupportCenterBundle\Entity\ArticleFeedback();
  641.         //                 // $articleBadge->setDescription('');
  642.         //                 $articleFeedback->setIsHelpful($isArticleHelpful);
  643.         //                 $articleFeedback->setArticle($article);
  644.         //                 $articleFeedback->setRatedCustomer($user);
  645.         //                 $articleFeedback->setCreatedAt(new \DateTime('now'));
  646.         //             } else {
  647.         //                 $articleFeedback->setIsHelpful($isArticleHelpful);
  648.         //                 $response['content']['alertMessage'] = 'Feedback updated successfully.';
  649.         //             }
  650.         //             $entityManager->persist($articleFeedback);
  651.         //             $entityManager->flush();
  652.         //         } else {
  653.         //             $response['content']['alertMessage'] = 'Invalid feedback provided.';
  654.         //         }
  655.         //     } else {
  656.         //         $response['content']['alertMessage'] = 'Article not found.';
  657.         //     }
  658.         // } else {
  659.         //     $response['content']['alertMessage'] = 'You need to login to your account before can perform this action.';
  660.         // }
  661.         return new Response(json_encode($response['content']), $response['code'], ['Content-Type: application/json']);
  662.     }
  663.     /**
  664.      * @Route("/api/knowledgebase/documents", name="helpdesk_knowledgebase_documents_api", methods={"GET", "OPTIONS"})
  665.      */
  666.     public function getKnowledgebaseDocuments(Request $request)
  667.     {
  668.         $this->isKnowledgebaseActive();
  669.         
  670.         $entityManager $this->getDoctrine()->getManager();
  671.         $articleRepository $entityManager->getRepository('UVDeskSupportCenterBundle:Article');
  672.         
  673.         // Obtener todos los artículos activos
  674.         $query $entityManager->createQueryBuilder()
  675.             ->select('a')
  676.             ->from('UVDeskSupportCenterBundle:Article''a')
  677.             ->where('a.status = :status')
  678.             ->setParameter('status'1);
  679.             
  680.         // Ejecutar la consulta para obtener todos los artículos
  681.         $articles $query->getQuery()->getResult();
  682.         
  683.         // Formatear los resultados
  684.         $documents = [];
  685.         $searchQuery $request->query->get('search');
  686.         $searchPerformed = !empty($searchQuery);
  687.         
  688.         foreach ($articles as $article) {
  689.             // Obtener el contenido del artículo
  690.             $content $article->getContent();
  691.             
  692.             // Inicializar variables
  693.             $documentName 'TEC' $article->getId() . ' - ' $article->getName();
  694.             $documentUrl null;
  695.             $linkText '';
  696.             $includeDocument true;
  697.             
  698.             // Información de depuración
  699.             $contentDebug = [
  700.                 'articleId' => $article->getId(),
  701.                 'hasContent' => !empty($content),
  702.                 'contentLength' => !empty($content) ? strlen($content) : 0,
  703.             ];
  704.             
  705.             // Buscar enlaces .pdf en el contenido
  706.             if (!empty($content)) {
  707.                 // Vista previa del contenido
  708.                 $contentPreview substr($content0300) . (strlen($content) > 300 '...' '');
  709.                 $contentDebug['contentPreview'] = $contentPreview;
  710.                 
  711.                 // Contar menciones de PDF y enlaces
  712.                 $contentDebug['pdfMentions'] = substr_count(strtolower($content), '.pdf');
  713.                 $contentDebug['linkMentions'] = substr_count(strtolower($content), 'href=');
  714.                 
  715.                 // Buscar enlaces dentro de etiquetas <a href>
  716.                 preg_match_all('/<a\s+[^>]*href=["\']([^"\']+)["\'][^>]*>([^<]+)<\/a>/i'$content$matches);
  717.                 
  718.                 if (!empty($matches[1])) {
  719.                     // Filtrar solo los enlaces relevantes (PDF o softguardtv.com o otros recursos)
  720.                     $relevantLinks = [];
  721.                     $relevantTexts = [];
  722.                     
  723.                     foreach ($matches[1] as $index => $link) {
  724.                         // Aceptar si es un PDF o contiene softguardtv.com o knowledge
  725.                         if (preg_match('/\.pdf$/i'$link) || 
  726.                             strpos($link'softguardtv.com') !== false || 
  727.                             strpos($link'knowledge') !== false ||
  728.                             strpos($link'courses') !== false ||
  729.                             strpos($link'lectures') !== false) {
  730.                             $relevantLinks[] = $link;
  731.                             $relevantTexts[] = $matches[2][$index] ?? '';
  732.                         }
  733.                     }
  734.                     
  735.                     // Guardar enlaces y textos relevantes
  736.                     if (!empty($relevantLinks)) {
  737.                         $contentDebug['foundLinks'] = $relevantLinks;
  738.                         $contentDebug['linkTexts'] = $relevantTexts;
  739.                         
  740.                         // Usar el primer enlace encontrado
  741.                         $documentUrl $relevantLinks[0];
  742.                         $linkText = !empty($relevantTexts[0]) ? trim($relevantTexts[0]) : '';
  743.                         
  744.                         // Usar texto del enlace como nombre
  745.                         if (!empty($linkText)) {
  746.                             $documentName $linkText;
  747.                         }
  748.                     }
  749.                 } else {
  750.                     // Búsqueda alternativa para URLs
  751.                     preg_match_all('/(https?:\/\/[^\s"\'<>]+)/i'$content$altMatches);
  752.                     
  753.                     if (!empty($altMatches[0])) {
  754.                         // Filtrar enlaces relevantes
  755.                         $relevantLinks = [];
  756.                         foreach ($altMatches[0] as $link) {
  757.                             if (preg_match('/\.pdf$/i'$link) || 
  758.                                 strpos($link'softguardtv.com') !== false || 
  759.                                 strpos($link'knowledge') !== false ||
  760.                                 strpos($link'courses') !== false ||
  761.                                 strpos($link'lectures') !== false) {
  762.                                 $relevantLinks[] = $link;
  763.                             }
  764.                         }
  765.                         
  766.                         if (!empty($relevantLinks)) {
  767.                             $contentDebug['foundLinks'] = $relevantLinks;
  768.                             $documentUrl $relevantLinks[0];
  769.                         }
  770.                     }
  771.                 }
  772.                 
  773.                 // Si se está realizando una búsqueda, verificar si el término está en el contenido
  774.                 if ($searchPerformed) {
  775.                     // Buscar en el contenido completo (incluye texto y enlaces)
  776.                     $includeDocument = (
  777.                         stripos($content$searchQuery) !== false || 
  778.                         stripos($documentName$searchQuery) !== false || 
  779.                         (!empty($documentUrl) && stripos($documentUrl$searchQuery) !== false) ||
  780.                         (!empty($linkText) && stripos($linkText$searchQuery) !== false)
  781.                     );
  782.                     
  783.                     $contentDebug['searchPerformed'] = true;
  784.                     $contentDebug['searchTerm'] = $searchQuery;
  785.                     $contentDebug['matchFound'] = $includeDocument;
  786.                 }
  787.             }
  788.             
  789.             // Si no se encontró URL, usar formato estándar
  790.             if (empty($documentUrl)) {
  791.                 $baseDocumentName $article->getName();
  792.                 $documentUrl 'https://softguard.com/knowledge/TEC' $article->getId() . '_' $baseDocumentName '.pdf';
  793.                 $contentDebug['usingFallbackUrl'] = true;
  794.             }
  795.             
  796.             // Solo incluir el documento si pasa los filtros de búsqueda
  797.             if ($includeDocument) {
  798.                 $documents[] = [
  799.                     'id' => $article->getId(),
  800.                     'name' => $documentName,
  801.                     'url' => $documentUrl,
  802.                     'views' => $article->getViewed(),
  803.                     'dateAdded' => $article->getDateAdded() ? $article->getDateAdded()->format('Y-m-d H:i:s') : null,
  804.                     'contentDebug' => $contentDebug
  805.                 ];
  806.             }
  807.         }
  808.         
  809.         // Ordenar por popularidad (vistas)
  810.         usort($documents, function($a$b) {
  811.             return $b['views'] - $a['views'];
  812.         });
  813.         
  814.         // Devolver respuesta JSON
  815.         return new JsonResponse([
  816.             'success' => true,
  817.             'documents' => $documents,
  818.             'totalFound' => count($documents),
  819.             'searchQuery' => $searchQuery
  820.         ]);
  821.     }
  822.     /**
  823.      * Función auxiliar para convertir texto en un slug
  824.      */
  825.     private function slugify($text)
  826.     {
  827.         // Reemplazar espacios con guiones bajos
  828.         $text str_replace(' ''_'$text);
  829.         // Eliminar caracteres especiales
  830.         $text preg_replace('/[^A-Za-z0-9\-_]/'''$text);
  831.         // Convertir a minúsculas
  832.         return strtolower($text);
  833.     }
  834. }