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

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