vendor/uvdesk/core-framework/Services/TicketService.php line 59

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\CoreFrameworkBundle\Services;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Doctrine\ORM\Query;
  5. use PDO;
  6. use Doctrine\DBAL\Driver\PDO\Connection as PDOConnection;
  7. use Symfony\Component\DependencyInjection\ContainerInterface;
  8. use Symfony\Component\EventDispatcher\GenericEvent;
  9. use Symfony\Component\Filesystem\Filesystem;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\HttpFoundation\RequestStack;
  13. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  14. use Symfony\Component\Yaml\Yaml;
  15. use UVDesk\CommunityPackages\UVDesk\CustomFields\Entity;
  16. use UVDesk\CommunityPackages\UVDesk\CustomFields\Entity as CommunityPackageEntities;
  17. use Webkul\UVDesk\AutomationBundle\Entity\PreparedResponses;
  18. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  19. use Webkul\UVDesk\CoreFrameworkBundle\Entity\AgentActivity;
  20. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
  21. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Thread;
  22. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Tag;
  23. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  24. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketStatus;
  25. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketPriority;
  26. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  27. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Website;
  28. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportGroup;
  29. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportTeam;
  30. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportLabel;
  31. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SavedReplies;
  32. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  33. use Webkul\UVDesk\CoreFrameworkBundle\Utils\TokenGenerator;
  34. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  35. use Webkul\UVDesk\CoreFrameworkBundle\Services\FileUploadService;
  36. use UVDesk\CommunityPackages\UVDesk\CustomFields\Entity\TicketCustomFieldsValues;
  37. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  38. use Webkul\UVDesk\MailboxBundle\Utils\Mailbox\Mailbox;
  39. use Webkul\UVDesk\MailboxBundle\Utils\MailboxConfiguration;
  40. use Webkul\UVDesk\MailboxBundle\Utils\IMAP\Configuration as ImapConfiguration;
  41. use Webkul\UVDesk\SupportCenterBundle\Entity\Article;
  42. use Webkul\UVDesk\SupportCenterBundle\Entity\KnowledgebaseWebsite;
  43. use Webkul\UVDesk\MailboxBundle\Services\MailboxService;
  44. use Doctrine\DBAL\Connection;
  45. use Symfony\Component\HttpFoundation\JsonResponse;
  46. class TicketService
  47. {
  48.     const PATH_TO_CONFIG '/config/packages/uvdesk_mailbox.yaml';
  49.     protected $container;
  50.     protected $requestStack;
  51.     protected $entityManager;
  52.     protected $fileUploadService;
  53.     protected $userService;
  54.     
  55.     public function __construct(
  56.         ContainerInterface $container
  57.         RequestStack $requestStack
  58.         EntityManagerInterface $entityManager
  59.         FileUploadService $fileUploadService,
  60.         UserService $userService
  61.         MailboxService $mailboxService
  62.     ) {
  63.         $this->container $container;
  64.         $this->requestStack $requestStack;
  65.         $this->entityManager $entityManager;
  66.         $this->fileUploadService $fileUploadService;
  67.         $this->userService $userService;
  68.         $this->mailboxService $mailboxService;
  69.     }
  70.     public function getPathToConfigurationFile()
  71.     {
  72.         return $this->container->get('kernel')->getProjectDir() . self::PATH_TO_CONFIG;
  73.     }
  74.     public function generateRandomEmailReferenceId()
  75.     {
  76.         $emailDomain null;
  77.         $mailbox $this->mailboxService->parseMailboxConfigurations()->getDefaultMailbox();
  78.         if (!empty($mailbox)) {
  79.             $smtpConfiguration $mailbox->getSmtpConfiguration();
  80.             if (!empty($smtpConfiguration)) {
  81.                 $emailDomain substr($smtpConfiguration->getUsername(), strpos($smtpConfiguration->getUsername(), '@'));
  82.             }
  83.         }
  84.         if (!empty($emailDomain)) {
  85.             return sprintf("<%s%s>"TokenGenerator::generateToken(20'0123456789abcdefghijklmnopqrstuvwxyz'), $emailDomain);
  86.         }
  87.         return null;
  88.     }
  89.     // @TODO: Refactor this out of this service. Use UserService::getSessionUser() instead.
  90.     public function getUser()
  91.     {
  92.         return $this->container->get('user.service')->getCurrentUser();
  93.     }
  94.     public function getDefaultType()
  95.     {
  96.         $typeCode $this->container->getParameter('uvdesk.default.ticket.type');
  97.         $ticketType $this->entityManager->getRepository(TicketType::class)->findOneByCode($typeCode);
  98.         return !empty($ticketType) ? $ticketType null;
  99.     }
  100.     public function getDefaultStatus()
  101.     {
  102.         $statusCode $this->container->getParameter('uvdesk.default.ticket.status');
  103.         $ticketStatus $this->entityManager->getRepository(TicketStatus::class)->findOneByCode($statusCode);
  104.         return !empty($ticketStatus) ? $ticketStatus null;
  105.     }
  106.     public function getDefaultPriority()
  107.     {
  108.         $priorityCode $this->container->getParameter('uvdesk.default.ticket.priority');
  109.         $ticketPriority $this->entityManager->getRepository(TicketPriority::class)->findOneByCode($priorityCode);
  110.         return !empty($ticketPriority) ? $ticketPriority null;
  111.     }
  112.     public function appendTwigSnippet($snippet '')
  113.     {
  114.         switch ($snippet) {
  115.             case 'createMemberTicket':
  116.                 return $this->getMemberCreateTicketSnippet();
  117.                 break;
  118.             default:
  119.                 break;
  120.         }
  121.         return '';
  122.     }
  123.     public function getMemberCreateTicketSnippet()
  124.     {   
  125.         $twigTemplatingEngine $this->container->get('twig');
  126.         $ticketTypeCollection $this->entityManager->getRepository(TicketType::class)->findByIsActive(true);
  127.         
  128.         try {
  129.             if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  130.                 $headerCustomFields $this->container->get('uvdesk_package_custom_fields.service')->getCustomFieldsArray('user');
  131.             } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  132.                 $headerCustomFields $this->container->get('uvdesk_package_form_component.service')->getCustomFieldsArray('user');
  133.             }
  134.         } catch (\Exception $e) {
  135.             // @TODO: Log execption message
  136.         }
  137.         return $twigTemplatingEngine->render('@UVDeskCoreFramework/Snippets/createMemberTicket.html.twig', [
  138.             'ticketTypeCollection' => $ticketTypeCollection,
  139.             'headerCustomFields' => $headerCustomFields ?? null,
  140.         ]);
  141.     }
  142.     public function getCustomerCreateTicketCustomFieldSnippet()
  143.     {
  144.         try {
  145.             if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  146.                 $customFields $this->container->get('uvdesk_package_custom_fields.service')->getCustomFieldsArray('customer');
  147.             } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  148.                 $customFields $this->container->get('uvdesk_package_form_component.service')->getCustomFieldsArray('customer');
  149.             }
  150.         } catch (\Exception $e) {
  151.             // @TODO: Log execption message
  152.         }
  153.         return $customFields ?? null;
  154.     }
  155.     public function createTicket(array $params = [])
  156.     {
  157.         $thread $this->entityManager->getRepository(Thread::class)->findOneByMessageId($params['messageId']);
  158.         if (empty($thread)) {
  159.             $user $this->entityManager->getRepository(User::class)->findOneByEmail($params['from']);
  160.             if (empty($user) || null == $user->getCustomerInstance()) {
  161.                 $role $this->entityManager->getRepository(SupportRole::class)->findOneByCode($params['role']);
  162.                 if (empty($role)) {
  163.                     throw new \Exception("The requested role '" $params['role'] . "' does not exist.");
  164.                 }
  165.                 
  166.                 // Create User Instance
  167.                 $user $this->container->get('user.service')->createUserInstance($params['from'], $params['name'], $role, [
  168.                     'source' => strtolower($params['source']),
  169.                     'active' => true,
  170.                 ]);
  171.             }
  172.             $params['role'] = 4;
  173.             $params['mailboxEmail'] = current($params['replyTo']); 
  174.             $params['customer'] = $params['user'] = $user;
  175.             return $this->createTicketBase($params);
  176.         }
  177.         return;
  178.     }
  179.     public function createTicketBase(array $ticketData = [])
  180.     {
  181.         if ('email' == $ticketData['source']) {
  182.             try {
  183.                 if (array_key_exists('UVDeskMailboxBundle'$this->container->getParameter('kernel.bundles'))) {
  184.                     $mailbox $this->mailboxService->getMailboxByEmail($ticketData['mailboxEmail']);
  185.                 }
  186.             } catch (\Exception $e) {
  187.                 // No mailbox found for this email. Skip ticket creation.
  188.                 return;
  189.             }
  190.         }
  191.         // Set Defaults
  192.         $ticketType = !empty($ticketData['type']) ? $ticketData['type'] : $this->getDefaultType();
  193.         $ticketStatus = !empty($ticketData['status']) ? $ticketData['status'] : $this->getDefaultStatus();
  194.         $ticketPriority = !empty($ticketData['priority']) ? $ticketData['priority'] : $this->getDefaultPriority();
  195.         if ('email' == $ticketData['source']) {
  196.             $ticketMessageId = !empty($ticketData['messageId']) ? $ticketData['messageId'] : null;
  197.         } else {
  198.             $ticketMessageId $this->generateRandomEmailReferenceId();
  199.         }
  200.         $ticketData['type'] = $ticketType;
  201.         $ticketData['status'] = $ticketStatus;
  202.         $ticketData['priority'] = $ticketPriority;
  203.         $ticketData['messageId'] = $ticketMessageId;
  204.         $ticketData['isTrashed'] = false;
  205.         $ticket = new Ticket();
  206.         foreach ($ticketData as $property => $value) {
  207.             $callable 'set' ucwords($property);
  208.             if (method_exists($ticket$callable)) {
  209.                 $ticket->$callable($value);
  210.             }
  211.         }
  212.         $this->entityManager->persist($ticket);
  213.         $this->entityManager->flush();
  214.         return $this->createThread($ticket$ticketData);
  215.     }
  216.     
  217.     public function createThread(Ticket $ticket, array $threadData)
  218.     {
  219.         $threadData['isLocked'] = 0;
  220.       
  221.         if ('forward' === $threadData['threadType']) {
  222.             $threadData['replyTo'] = $threadData['to'];
  223.         }
  224.         $collaboratorEmails array_merge(!empty($threadData['cccol']) ? $threadData['cccol'] : [], !empty($threadData['cc']) ? $threadData['cc'] : []);
  225.         
  226.         if (!empty($collaboratorEmails)) {
  227.             $threadData['cc'] = $collaboratorEmails;
  228.         }
  229.    
  230.         $thread = new Thread();
  231.         $thread->setTicket($ticket);
  232.         $thread = new Thread();
  233.         $thread->setTicket($ticket);
  234.         // Determine which typeId to use
  235.         if (isset($threadData['typeId'])) {
  236.             // Use the provided typeId from $threadData if it's defined
  237.             $typeId $threadData['typeId'];
  238.         } else {
  239.             // Otherwise, get the type id from the ticket
  240.             $type $ticket->getType();
  241.             if ($type) {
  242.                 $typeId $type->getId();  // Get the id from the ticket's type object
  243.             } else {
  244.                 $typeId null;  // Handle the case where the ticket has no type
  245.             }
  246.         }
  247.         $thread->setTypeId($typeId);
  248.         $thread->setCreatedAt(new \DateTime());
  249.         $thread->setUpdatedAt(new \DateTime());
  250.         
  251.         if (isset($threadData['timeSpent']) && !empty($threadData['timeSpent'])) {
  252.         $thread->setTimeSpent($threadData['timeSpent']);
  253.             }
  254.         if ($threadData['threadType'] != "note") {
  255.             foreach ($threadData as $property => $value) {
  256.                 if (!empty($value)) {
  257.                     $callable 'set' ucwords($property);
  258.                     if (method_exists($thread$callable)) {
  259.                         $thread->$callable($value);
  260.                     }
  261.                 }
  262.             }
  263.         } else {
  264.             $this->setTicketNotePlaceholderValue($thread$threadData$ticket);
  265.         }
  266.         // Update ticket reference ids is thread message id is defined
  267.         if (null != $thread->getMessageId() && false === strpos($ticket->getReferenceIds(), $thread->getMessageId())) {
  268.             $updatedReferenceIds $ticket->getReferenceIds() . ' ' $thread->getMessageId();            
  269.             $ticket->setReferenceIds($updatedReferenceIds);
  270.             $this->entityManager->persist($ticket);
  271.         }
  272.         if ('reply' === $threadData['threadType']) {
  273.             if ('agent' === $threadData['createdBy']) {
  274.                 // Ticket has been updated by support agents, mark as agent replied | customer view pending
  275.                 $ticket->setIsCustomerViewed(false);
  276.                 $ticket->setIsReplied(true);
  277.                 $customerName $ticket->getCustomer()->getFirstName().' '.$ticket->getCustomer()->getLastName();
  278.                 $agentActivity = new AgentActivity();
  279.                 $agentActivity->setThreadType('reply');
  280.                 $agentActivity->setTicket($ticket);
  281.                 $agentActivity->setAgent($thread->getUser());
  282.                 $agentActivity->setCustomerName($customerName);
  283.                 $agentActivity->setAgentName('agent');
  284.                 $agentActivity->setCreatedAt(new \DateTime());
  285.                 $this->entityManager->persist($agentActivity);
  286.             } else {
  287.                 // Ticket has been updated by customer, mark as agent view | reply pending
  288.                 $ticket->setIsAgentViewed(false);
  289.                 $ticket->setIsReplied(false);
  290.             }
  291.             $this->entityManager->persist($ticket);
  292.         } else if ('create' === $threadData['threadType']) {
  293.             $ticket->setIsReplied(false);
  294.             $this->entityManager->persist($ticket);
  295.             $customerName $ticket->getCustomer()->getFirstName().' '.$ticket->getCustomer()->getLastName();
  296.             $agentActivity = new AgentActivity();
  297.             $agentActivity->setThreadType('create');
  298.             $agentActivity->setTicket($ticket);
  299.             $agentActivity->setAgent($thread->getUser());
  300.             $agentActivity->setCustomerName($customerName );
  301.             $agentActivity->setAgentName('agent');
  302.             $agentActivity->setCreatedAt(new \DateTime());
  303.             $this->entityManager->persist($agentActivity);
  304.         }
  305.         
  306.         $ticket->currentThread $this->entityManager->getRepository(Thread::class)->getTicketCurrentThread($ticket);
  307.         
  308.         $this->entityManager->persist($thread);
  309.         $this->entityManager->flush();
  310.         
  311.         $ticket->createdThread $thread;
  312.         // Uploading Attachments
  313.         if (!empty($threadData['attachments'])) {
  314.             if ('email' == $threadData['source']) {
  315.                 $this->saveThreadEmailAttachments($thread$threadData['attachments']);
  316.             } else if (!empty($threadData['attachments'])) {
  317.                 $this->saveThreadAttachment($thread$threadData['attachments']);
  318.             }
  319.         }
  320.         return $thread;
  321.     }
  322.     public function setTicketNotePlaceholderValue($thread$threadData$ticket)
  323.     {
  324.         if (!empty($threadData)) {
  325.             foreach ($threadData as $property => $value) {
  326.                 if (!empty($value)) {
  327.                     $callable 'set' ucwords($property);
  328.                     if (method_exists($thread$callable)) {
  329.                         if($callable != "setMessage") {
  330.                             $thread->$callable($value);
  331.                         } else {
  332.                             $notesPlaceholders $this->getNotePlaceholderValues($ticket'customer');
  333.                             $content $value;
  334.                             foreach ($notesPlaceholders as $key => $val) {
  335.                                 if(strpos($value"{%$key%}") !== false){
  336.                                     $content strtr($value, ["{%$key%}" => $val"{% $key %}" => $val]);
  337.                                 }
  338.                             }
  339.                             
  340.                             $content stripslashes($content);
  341.                             $thread->$callable($content);
  342.                         }
  343.                     }
  344.                 }
  345.             }
  346.         }
  347.     }
  348.     public function saveThreadAttachment($thread, array $attachments)
  349.     {
  350.         $prefix 'threads/' $thread->getId();
  351.         $uploadManager $this->container->get('uvdesk.core.file_system.service')->getUploadManager();
  352.         foreach ($attachments as $attachment) {
  353.             $uploadedFileAttributes $uploadManager->uploadFile($attachment$prefix);
  354.             if (!empty($uploadedFileAttributes['path'])) {
  355.                 ($threadAttachment = new Attachment())
  356.                     ->setThread($thread)
  357.                     ->setName($uploadedFileAttributes['name'])
  358.                     ->setPath($uploadedFileAttributes['path'])
  359.                     ->setSize($uploadedFileAttributes['size'])
  360.                     ->setContentType($uploadedFileAttributes['content-type']);
  361.                 
  362.                 $this->entityManager->persist($threadAttachment);
  363.             }
  364.         }
  365.         $this->entityManager->flush();
  366.     }
  367.     public function saveThreadEmailAttachments($thread, array $attachments)
  368.     {
  369.         $prefix 'threads/' $thread->getId();
  370.         $uploadManager $this->container->get('uvdesk.core.file_system.service')->getUploadManager();
  371.         
  372.         // Upload thread attachments
  373.         foreach ($attachments as $attachment) {
  374.             $uploadedFileAttributes $uploadManager->uploadEmailAttachment($attachment$prefix);
  375.             
  376.             if (!empty($uploadedFileAttributes['path'])) {
  377.                 ($threadAttachment = new Attachment())
  378.                     ->setThread($thread)
  379.                     ->setName($uploadedFileAttributes['name'])
  380.                     ->setPath($uploadedFileAttributes['path'])
  381.                     ->setSize($uploadedFileAttributes['size'])
  382.                     ->setContentType($uploadedFileAttributes['content-type']);
  383.                 
  384.                 $this->entityManager->persist($threadAttachment);
  385.             }
  386.         }
  387.         $this->entityManager->flush();
  388.     }
  389.     public function getTypes($visibilityFilter = [])
  390.     {
  391.         static $types;
  392.         if (null !== $types)
  393.             return $types;
  394.     
  395.         $qb $this->entityManager->createQueryBuilder();
  396.         $qb->select('tp.id''tp.code AS name')
  397.             ->from(TicketType::class, 'tp')
  398.             ->where('tp.isActive = 1'// Ensure only active types are fetched
  399.             ->orderBy('tp.code''ASC');
  400.     
  401.         // Apply visibility filter (0 = Customer, 2 = Both)
  402.         if (!empty($visibilityFilter)) {
  403.             $qb->andWhere('tp.visibility IN (:visibility)')
  404.             ->setParameter('visibility'$visibilityFilter);
  405.         }
  406.     
  407.         return $types $qb->getQuery()->getArrayResult();
  408.     }
  409.     public function getStatus()
  410.     {
  411.         static $statuses;
  412.         if (null !== $statuses)
  413.             return $statuses;
  414.         $qb $this->entityManager->createQueryBuilder();
  415.         $qb->select('ts')->from(TicketStatus::class, 'ts');
  416.         // $qb->orderBy('ts.sortOrder', Criteria::ASC);
  417.         return $statuses $qb->getQuery()->getArrayResult();
  418.     }
  419.     public function getTicketTotalThreads($ticketId)
  420.     {
  421.         $qb $this->entityManager->createQueryBuilder();
  422.         $qb->select('COUNT(th.id) as threadCount')->from(Ticket::class, 't')
  423.             ->leftJoin('t.threads''th')
  424.             ->andWhere('t.id = :ticketId')
  425.             ->andWhere('th.threadType = :threadType')
  426.             ->setParameter('threadType','reply')
  427.             ->setParameter('ticketId'$ticketId);
  428.         $qb $this->entityManager->createQueryBuilder();
  429.         $qb->select('COUNT(t.id) as threadCount')->from(Thread::class, 't')
  430.             ->andWhere('t.ticket = :ticketId')
  431.             ->andWhere('t.threadType = :threadType')
  432.             ->setParameter('threadType','reply')
  433.             ->setParameter('ticketId'$ticketId);
  434.         return $qb->getQuery()->getSingleScalarResult();
  435.     }
  436.     public function getTicketTags($request null)
  437.     {
  438.         $qb $this->entityManager->createQueryBuilder();
  439.         $qb->select('tg')->from(Tag::class, 'tg');
  440.         if($request) {
  441.             $qb->andwhere("tg.name LIKE :tagName");
  442.             $qb->setParameter('tagName''%'.urldecode($request->query->get('query')).'%');
  443.             $qb->andwhere("tg.id NOT IN (:ids)");
  444.             $qb->setParameter('ids'explode(',',urldecode($request->query->get('not'))));
  445.         }
  446.         return $qb->getQuery()->getArrayResult();
  447.     }
  448.     
  449.     public function getAllMembersTicketCollection(Request $request)
  450.     {
  451.        
  452.         $params $request->query->all();
  453.         $activeUser $this->container->get('user.service')->getSessionUser();
  454.         $activeUserTimeZone $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  455.         $agentTimeZone = !empty($activeUser->getTimezone()) ? $activeUser->getTimezone() : $activeUserTimeZone->getTimezone();
  456.         $agentTimeFormat = !empty($activeUser->getTimeformat()) ? $activeUser->getTimeformat() : $activeUserTimeZone->getTimeformat();
  457.         $ticketRepository $this->entityManager->getRepository(Ticket::class);
  458.         $website $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'helpdesk']);
  459.         $timeZone $website->getTimezone();
  460.         $timeFormat $website->getTimeformat();
  461.         $supportGroupReference $this->entityManager->getRepository(User::class)->getUserSupportGroupReferences($activeUser);
  462.         $supportTeamReference  $this->entityManager->getRepository(User::class)->getUserSupportTeamReferences($activeUser);
  463.         // Get base query
  464.         $baseQuery $ticketRepository->prepareBaseTicketQuery($activeUser$supportGroupReference$supportTeamReference$params);
  465.         $ticketTabs $ticketRepository->getTicketTabDetails($activeUser$supportGroupReference$supportTeamReference$params);
  466.         // Apply Pagination
  467.         $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  468.         $itemsLimit 100000;
  469.         if (isset($params['repliesLess']) || isset($params['repliesMore'])) {
  470.             $paginationOptions = ['wrap-queries' => true];
  471.             $paginationQuery $baseQuery->getQuery()
  472.                 ->setHydrationMode(Query::HYDRATE_ARRAY);
  473.         } else {
  474.             $paginationOptions = ['distinct' => true];
  475.             $paginationQuery $baseQuery->getQuery()
  476.                 ->setHydrationMode(Query::HYDRATE_ARRAY)
  477.                 ->setHint('knp_paginator.count', isset($params['status']) ? $ticketTabs[$params['status']] : $ticketTabs[1]);
  478.         }
  479.         $pagination $this->container->get('knp_paginator')->paginate($paginationQuery$pageNumber$itemsLimit$paginationOptions);
  480.         // Process Pagination Response
  481.         $ticketCollection = [];
  482.         $paginationParams $pagination->getParams();
  483.         $paginationData $pagination->getPaginationData();
  484.         $paginationParams['page'] = 'replacePage';
  485.         $paginationData['url'] = '#' $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  486.         // $container->get('default.service')->buildSessionUrl('ticket',$queryParameters);
  487.         $ticketThreadCountQueryTemplate $this->entityManager->createQueryBuilder()
  488.             ->select('COUNT(thread.id) as threadCount')
  489.             ->from(Ticket::class, 'ticket')
  490.             ->leftJoin('ticket.threads''thread')
  491.             ->where('ticket.id = :ticketId')
  492.             ->andWhere('thread.threadType = :threadType')->setParameter('threadType''reply');
  493.         
  494.         foreach ($pagination->getItems() as $ticketDetails) {
  495.             $ticket array_shift($ticketDetails);
  496.             $ticketThreadCountQuery = clone $ticketThreadCountQueryTemplate;
  497.             $ticketThreadCountQuery->setParameter('ticketId'$ticket['id']);
  498.             $totalTicketReplies = (int) $ticketThreadCountQuery->getQuery()->getSingleScalarResult();
  499.             $ticketHasAttachments false;
  500.             $dbTime $ticket['createdAt'];
  501.             
  502.             $formattedTime$this->fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat);
  503.             $currentDateTime  = new \DateTime('now');
  504.             if($this->getLastReply($ticket['id'])) {
  505.                 $lastRepliedTime 
  506.                 $this->time2string($currentDateTime->getTimeStamp() - $this->getLastReply($ticket['id'])['createdAt']->getTimeStamp());
  507.             } else {
  508.                 $lastRepliedTime 
  509.                 $this->time2string($currentDateTime->getTimeStamp() - $ticket['createdAt']->getTimeStamp());
  510.             }
  511.             $ticketResponse = [
  512.                 'id' => $ticket['id'],
  513.                 'subject' => $ticket['subject'],
  514.                 'isStarred' => $ticket['isStarred'],
  515.                 'isAgentView' => $ticket['isAgentViewed'],
  516.                 'isTrashed' => $ticket['isTrashed'],
  517.                 'source' => $ticket['source'],
  518.                 'group' => $ticketDetails['groupName'],
  519.                 'team' => $ticketDetails['teamName'],
  520.                 'priority' => $ticket['priority'],
  521.                 'type' => $ticketDetails['typeName'],
  522.                 'timestamp' => $formattedTime['dateTimeZone'],
  523.                 'formatedCreatedAt' => $formattedTime['dateTimeZone']->format($formattedTime['timeFormatString']),
  524.                 'totalThreads' => $totalTicketReplies,
  525.                 'agent' => null,
  526.                 'customer' => null,
  527.                 'hasAttachments' => $ticketHasAttachments,
  528.                 'lastReplyTime' => $lastRepliedTime
  529.             ];
  530.            
  531.             if (!empty($ticketDetails['agentId'])) {
  532.                 $ticketResponse['agent'] = [
  533.                     'id' => $ticketDetails['agentId'],
  534.                     'name' => $ticketDetails['agentName'],
  535.                     'smallThumbnail' => $ticketDetails['smallThumbnail'],
  536.                 ];
  537.             }
  538.             if (!empty($ticketDetails['customerId'])) {
  539.                 $ticketResponse['customer'] = [
  540.                     'id' => $ticketDetails['customerId'],
  541.                     'name' => $ticketDetails['customerName'],
  542.                     'email' => $ticketDetails['customerEmail'],
  543.                     'smallThumbnail' => $ticketDetails['customersmallThumbnail'],
  544.                 ];
  545.             }
  546.             array_push($ticketCollection$ticketResponse);
  547.         }
  548.          
  549.         return [
  550.             'tickets' => $ticketCollection,
  551.             'pagination' => $paginationData,
  552.             'tabs' => $ticketTabs,
  553.             'labels' => [
  554.                 'predefind' => $this->getPredefindLabelDetails($activeUser$supportGroupReference$supportTeamReference$params),
  555.                 'custom' => $this->getCustomLabelDetails($this->container),
  556.             ],
  557.           
  558.         ];
  559.     }
  560.     
  561.     public function paginateMembersTicketCollection(Request $request)
  562.     {
  563.         $params $request->query->all();
  564.         $activeUser $this->container->get('user.service')->getSessionUser();
  565.         $activeUserTimeZone $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  566.         $agentTimeZone = !empty($activeUser->getTimezone()) ? $activeUser->getTimezone() : $activeUserTimeZone->getTimezone();
  567.         $agentTimeFormat = !empty($activeUser->getTimeformat()) ? $activeUser->getTimeformat() : $activeUserTimeZone->getTimeformat();
  568.         $ticketRepository $this->entityManager->getRepository(Ticket::class);
  569.         $website $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'helpdesk']);
  570.         $timeZone $website->getTimezone();
  571.         $timeFormat $website->getTimeformat();
  572.         $supportGroupReference $this->entityManager->getRepository(User::class)->getUserSupportGroupReferences($activeUser);
  573.         $supportTeamReference  $this->entityManager->getRepository(User::class)->getUserSupportTeamReferences($activeUser);
  574.         // Get base query
  575.         $baseQuery $ticketRepository->prepareBaseTicketQuery($activeUser$supportGroupReference$supportTeamReference$params);
  576.         $ticketTabs $ticketRepository->getTicketTabDetails($activeUser$supportGroupReference$supportTeamReference$params);
  577.         // Apply Pagination
  578.         $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  579.         $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $ticketRepository::DEFAULT_PAGINATION_LIMIT;
  580.         if (isset($params['repliesLess']) || isset($params['repliesMore'])) {
  581.             $paginationOptions = ['wrap-queries' => true];
  582.             $paginationQuery $baseQuery->getQuery()
  583.                 ->setHydrationMode(Query::HYDRATE_ARRAY);
  584.         } else {
  585.             $paginationOptions = ['distinct' => true];
  586.             $paginationQuery $baseQuery->getQuery()
  587.                 ->setHydrationMode(Query::HYDRATE_ARRAY)
  588.                 ->setHint('knp_paginator.count', isset($params['status']) ? $ticketTabs[$params['status']] : $ticketTabs[1]);
  589.         }
  590.         $pagination $this->container->get('knp_paginator')->paginate($paginationQuery$pageNumber$itemsLimit$paginationOptions);
  591.         // Process Pagination Response
  592.         $ticketCollection = [];
  593.         $paginationParams $pagination->getParams();
  594.         $paginationData $pagination->getPaginationData();
  595.         $paginationParams['page'] = 'replacePage';
  596.         $paginationData['url'] = '#' $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  597.         // $container->get('default.service')->buildSessionUrl('ticket',$queryParameters);
  598.         $ticketThreadCountQueryTemplate $this->entityManager->createQueryBuilder()
  599.             ->select('COUNT(thread.id) as threadCount')
  600.             ->from(Ticket::class, 'ticket')
  601.             ->leftJoin('ticket.threads''thread')
  602.             ->where('ticket.id = :ticketId')
  603.             ->andWhere('thread.threadType = :threadType')->setParameter('threadType''reply');
  604.         
  605.         foreach ($pagination->getItems() as $ticketDetails) {
  606.             $ticket array_shift($ticketDetails);
  607.             $ticketThreadCountQuery = clone $ticketThreadCountQueryTemplate;
  608.             $ticketThreadCountQuery->setParameter('ticketId'$ticket['id']);
  609.             $totalTicketReplies = (int) $ticketThreadCountQuery->getQuery()->getSingleScalarResult();
  610.             $ticketHasAttachments false;
  611.             $dbTime $ticket['createdAt'];
  612.             
  613.             $formattedTime$this->fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat);
  614.             $currentDateTime  = new \DateTime('now');
  615.             if($this->getLastReply($ticket['id'])) {
  616.                 $lastRepliedTime 
  617.                 $this->time2string($currentDateTime->getTimeStamp() - $this->getLastReply($ticket['id'])['createdAt']->getTimeStamp());
  618.             } else {
  619.                 $lastRepliedTime 
  620.                 $this->time2string($currentDateTime->getTimeStamp() - $ticket['createdAt']->getTimeStamp());
  621.             }
  622.             $ticketResponse = [
  623.                 'id' => $ticket['id'],
  624.                 'subject' => $ticket['subject'],
  625.                 'isStarred' => $ticket['isStarred'],
  626.                 'isAgentView' => $ticket['isAgentViewed'],
  627.                 'isTrashed' => $ticket['isTrashed'],
  628.                 'source' => $ticket['source'],
  629.                 'group' => $ticketDetails['groupName'],
  630.                 'team' => $ticketDetails['teamName'],
  631.                 'priority' => $ticket['priority'],
  632.                 'type' => $ticketDetails['typeName'],
  633.                 'timestamp' => $formattedTime['dateTimeZone'],
  634.                 'formatedCreatedAt' => $formattedTime['dateTimeZone']->format($formattedTime['timeFormatString']),
  635.                 'totalThreads' => $totalTicketReplies,
  636.                 'agent' => null,
  637.                 'customer' => null,
  638.                 'hasAttachments' => $ticketHasAttachments,
  639.                 'lastReplyTime' => $lastRepliedTime
  640.             ];
  641.            
  642.             if (!empty($ticketDetails['agentId'])) {
  643.                 $ticketResponse['agent'] = [
  644.                     'id' => $ticketDetails['agentId'],
  645.                     'name' => $ticketDetails['agentName'],
  646.                     'smallThumbnail' => $ticketDetails['smallThumbnail'],
  647.                 ];
  648.             }
  649.             if (!empty($ticketDetails['customerId'])) {
  650.                 $ticketResponse['customer'] = [
  651.                     'id' => $ticketDetails['customerId'],
  652.                     'name' => $ticketDetails['customerName'],
  653.                     'email' => $ticketDetails['customerEmail'],
  654.                     'contactNumber' => $ticketDetails['contactNumber'],
  655.                     'smallThumbnail' => $ticketDetails['customersmallThumbnail'],
  656.                 ];
  657.             }
  658.             array_push($ticketCollection$ticketResponse);
  659.         }
  660.          
  661.         return [
  662.             'tickets' => $ticketCollection,
  663.             'pagination' => $paginationData,
  664.             'tabs' => $ticketTabs,
  665.             'labels' => [
  666.                 'predefind' => $this->getPredefindLabelDetails($activeUser$supportGroupReference$supportTeamReference$params),
  667.                 'custom' => $this->getCustomLabelDetails($this->container),
  668.             ],
  669.           
  670.         ];
  671.     }
  672.     // Convert Timestamp to day/hour/min
  673.     Public function time2string($time) {
  674.         $d floor($time/86400);
  675.         $_d = ($d 10 '0' '').$d;
  676.         $h floor(($time-$d*86400)/3600);
  677.         $_h = ($h 10 '0' '').$h;
  678.         $m floor(($time-($d*86400+$h*3600))/60);
  679.         $_m = ($m 10 '0' '').$m;
  680.         $s $time-($d*86400+$h*3600+$m*60);
  681.         $_s = ($s 10 '0' '').$s;
  682.         $time_str "0 minutes";
  683.         if($_d != 00)
  684.             $time_str $_d." ".'days';
  685.         elseif($_h != 00)
  686.             $time_str $_h." ".'hours';
  687.         elseif($_m != 00)
  688.             $time_str $_m." ".'minutes';
  689.         return $time_str." "."ago";
  690.     }
  691.     public function getPredefindLabelDetails(User $currentUser, array $supportGroupIds = [], array $supportTeamIds = [], array $params = [])
  692.     {
  693.         $data = array();
  694.         $queryBuilder $this->entityManager->createQueryBuilder();
  695.         $ticketRepository $this->entityManager->getRepository(Ticket::class);
  696.         $queryBuilder->select('COUNT(DISTINCT ticket.id) as ticketCount')->from(Ticket::class, 'ticket');
  697.             
  698.         // // applyFilter according to permission
  699.         $queryBuilder->where('ticket.isTrashed != 1');
  700.         $userInstance $currentUser->getAgentInstance();
  701.         if (!empty($userInstance) &&  'ROLE_AGENT' == $userInstance->getSupportRole()->getCode() 
  702.         && $userInstance->getTicketAccesslevel() != 1) {
  703.             $supportGroupIds implode(','$supportGroupIds);
  704.             $supportTeamIds implode(','$supportTeamIds);
  705.             if ($userInstance->getTicketAccesslevel() == 4) {
  706.                 $queryBuilder->andwhere('ticket.agent = ' $currentUser->getId());
  707.             } elseif ($userInstance->getTicketAccesslevel() == 2) {
  708.                 $query '';
  709.                 if ($supportGroupIds){
  710.                     $query .= ' OR supportGroup.id IN('.$supportGroupIds.') ';
  711.                 }
  712.                 if ($supportTeamIds) {
  713.                     $query .= ' OR supportTeam.id IN('.$supportTeamIds.') ';
  714.                 }
  715.                 $queryBuilder->leftJoin('ticket.supportGroup''supportGroup')
  716.                             ->leftJoin('ticket.supportTeam''supportTeam')
  717.                             ->andwhere('( ticket.agent = ' $currentUser->getId().$query.')');
  718.                     
  719.             } elseif ($userInstance->getTicketAccesslevel() == 3) {
  720.                 $query '';
  721.                 if ($supportTeamIds) {
  722.                     $query .= ' OR supportTeam.id IN('.$supportTeamIds.') ';
  723.                 }
  724.                 $queryBuilder->leftJoin('ticket.supportGroup''supportGroup')
  725.                             ->leftJoin('ticket.supportTeam''supportTeam')
  726.                             ->andwhere('( ticket.agent = ' $currentUser->getId().$query')');
  727.             }
  728.         }
  729.         // for all tickets count
  730.         $data['all'] = $queryBuilder->getQuery()->getSingleScalarResult();
  731.         // for new tickets count
  732.         $newQb = clone $queryBuilder;
  733.         $newQb->andwhere('ticket.isNew = 1');
  734.         $data['new'] = $newQb->getQuery()->getSingleScalarResult();
  735.         // for unassigned tickets count
  736.         $unassignedQb = clone $queryBuilder;
  737.         $unassignedQb->andwhere("ticket.agent is NULL");
  738.         $data['unassigned'] = $unassignedQb->getQuery()->getSingleScalarResult();
  739.         // for unanswered ticket count
  740.         $unansweredQb = clone $queryBuilder;
  741.         $unansweredQb->andwhere('ticket.isReplied = 0');
  742.         $data['notreplied'] = $unansweredQb->getQuery()->getSingleScalarResult();
  743.         // for my tickets count
  744.         $mineQb = clone $queryBuilder;
  745.         $mineQb->andWhere("ticket.agent = :agentId")
  746.                 ->setParameter('agentId'$currentUser->getId());
  747.         $data['mine'] = $mineQb->getQuery()->getSingleScalarResult();
  748.         // for starred tickets count
  749.         $starredQb = clone $queryBuilder;
  750.         $starredQb->andwhere('ticket.isStarred = 1');
  751.         $data['starred'] = $starredQb->getQuery()->getSingleScalarResult();
  752.         // for trashed tickets count
  753.         $trashedQb = clone $queryBuilder;
  754.         $trashedQb->where('ticket.isTrashed = 1');
  755.         if ($currentUser->getRoles()[0] != 'ROLE_SUPER_ADMIN' && $userInstance->getTicketAccesslevel() != 1) {
  756.             $trashedQb->andwhere('ticket.agent = ' $currentUser->getId());
  757.         }
  758.         $data['trashed'] = $trashedQb->getQuery()->getSingleScalarResult();
  759.         return $data;
  760.     }
  761.     
  762.     public function paginateMembersTicketThreadCollection(Ticket $ticketRequest $request)
  763.     {
  764.         $params $request->query->all();
  765.         $entityManager $this->entityManager;
  766.         $activeUser $this->container->get('user.service')->getSessionUser();
  767.         $ticketTypeRepo $entityManager->getRepository(TicketType::class);
  768.         $activeUserTimeZone $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  769.         $agentTimeZone = !empty($activeUser->getTimezone()) ? $activeUser->getTimezone() : $activeUserTimeZone->getTimezone();
  770.         $agentTimeFormat = !empty($activeUser->getTimeformat()) ? $activeUser->getTimeformat() : $activeUserTimeZone->getTimeformat();
  771.         
  772.         $threadRepository $entityManager->getRepository(Thread::class);
  773.         $uvdeskFileSystemService $this->container->get('uvdesk.core.file_system.service');
  774.         // Get base query
  775.         $enableLockedThreads $this->container->get('user.service')->isAccessAuthorized('ROLE_AGENT_MANAGE_LOCK_AND_UNLOCK_THREAD');
  776.         $baseQuery $threadRepository->prepareBasePaginationRecentThreadsQuery($ticket$params$enableLockedThreads);
  777.         
  778.         // Apply Pagination
  779.         $paginationItemsQuery = clone $baseQuery;
  780.         $totalPaginationItems $paginationItemsQuery->select('COUNT(DISTINCT thread.id)')->getQuery()->getSingleScalarResult();
  781.         
  782.         $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  783.         $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $threadRepository::DEFAULT_PAGINATION_LIMIT;
  784.         
  785.         $paginationOptions = ['distinct' => true];
  786.         $paginationQuery $baseQuery->getQuery()->setHydrationMode(Query::HYDRATE_ARRAY)->setHint('knp_paginator.count', (int) $totalPaginationItems);
  787.         $pagination $this->container->get('knp_paginator')->paginate($paginationQuery$pageNumber$itemsLimit$paginationOptions);
  788.         // Process Pagination Response
  789.         $threadCollection = [];
  790.         $paginationParams $pagination->getParams();
  791.         $paginationData $pagination->getPaginationData();
  792.         $website $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'helpdesk']);
  793.         $timeZone $website->getTimezone();
  794.         $timeFormat $website->getTimeformat();
  795.         if (!empty($params['threadRequestedId'])) {
  796.             $requestedThreadCollection $baseQuery
  797.                 ->andWhere('thread.id >= :threadRequestedId')->setParameter('threadRequestedId', (int) $params['threadRequestedId'])
  798.                 ->getQuery()->getArrayResult();
  799.             
  800.             $totalRequestedThreads count($requestedThreadCollection);
  801.             $paginationData['current'] = ceil($totalRequestedThreads $threadRepository::DEFAULT_PAGINATION_LIMIT);
  802.             if ($paginationData['current'] > 1) {
  803.                 $paginationData['firstItemNumber'] = 1;
  804.                 $paginationData['lastItemNumber'] = $totalRequestedThreads;
  805.                 $paginationData['next'] = ceil(($totalRequestedThreads 1) / $threadRepository::DEFAULT_PAGINATION_LIMIT);
  806.             }
  807.         }
  808.         $paginationParams['page'] = 'replacePage';
  809.         $paginationData['url'] = '#' $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  810.         foreach ($pagination->getItems() as $threadDetails) {
  811.             $dbTime $threadDetails['createdAt'];
  812.             $formattedTime $this->fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat);
  813.             
  814.             // Fetch custom fields and their values for the provided thread_id
  815.             $customFields $entityManager->getRepository(TicketCustomFieldsValues::class)->findBy([
  816.                 'ThreadId' => $threadDetails['id']
  817.             ]);
  818.             $responseArray = [];
  819.             if (!empty($customFields)) {
  820.                 foreach ($customFields as $field) {
  821.                     $responseArray[] = [
  822.                         'custom_field_id' => $field->getTicketCustomFieldsValues()->getId(),
  823.                         'value' => $field->getValue(),
  824.                     ];
  825.                 }
  826.             }
  827.             
  828.             $typeId $threadDetails['typeId'] ?? null;
  829.             $typeCode "";
  830.             $typeDescription "";
  831.             if ($typeId) {
  832.                 $ticketType $ticketTypeRepo->find($typeId);
  833.                 if ($ticketType) {
  834.                     $typeCode $ticketType->getCode();
  835.                     $typeDescription $ticketType->getDescription();
  836.                 } else {
  837.                     $typeCode null;
  838.                     $typeDescription null;
  839.                 }
  840.             } else {
  841.                 $typeCode null;
  842.                 $typeDescription null;
  843.             }
  844.             $threadResponse = [
  845.                 'id' => $threadDetails['id'],
  846.                 'user' => null,
  847.                 'fullname' => null,
  848.                 'typeid' => $threadDetails['typeId'],
  849.                 'typeCode' => $typeCode,
  850.                 'typeDescription' => $typeDescription,
  851.                 'reply' => html_entity_decode($threadDetails['message']),
  852.                 'source' => $threadDetails['source'],
  853.                 'threadType' => $threadDetails['threadType'],
  854.                 'userType' => $threadDetails['createdBy'],
  855.                 'timestamp' => $formattedTime['dateTimeZone'],
  856.                 'formatedCreatedAt' => $formattedTime['dateTimeZone']->format($formattedTime['timeFormatString']),
  857.                 'bookmark' => $threadDetails['isBookmarked'],
  858.                 'isLocked' => $threadDetails['isLocked'],
  859.                 'replyTo' => $threadDetails['replyTo'],
  860.                 'cc' => $threadDetails['cc'],
  861.                 'bcc' => $threadDetails['bcc'],
  862.                 'attachments' => $threadDetails['attachments'],
  863.                 'timeSpent' => $threadDetails['timeSpent'],
  864.                 'customfields' => $responseArray
  865.             ];
  866.   
  867.             if (!empty($threadDetails['user'])) {
  868.                 $threadResponse['fullname'] = trim($threadDetails['user']['firstName'] . ' ' $threadDetails['user']['lastName']);
  869.                 $threadResponse['user'] = [
  870.                     'id' => $threadDetails['user']['id'],
  871.                     'smallThumbnail' => $threadDetails['user']['userInstance'][0]['profileImagePath'],
  872.                     'name' => $threadResponse['fullname'],
  873.                 ];
  874.             }
  875.             if (!empty($threadResponse['attachments'])) {
  876.                 $threadResponse['attachments'] = array_map(function ($attachment) use ($entityManager$uvdeskFileSystemService) {
  877.                     $attachmentReferenceObject $entityManager->getReference(Attachment::class, $attachment['id']);
  878.                     return $uvdeskFileSystemService->getFileTypeAssociations($attachmentReferenceObject);
  879.                 }, $threadResponse['attachments']);
  880.             }
  881.             array_push($threadCollection$threadResponse);
  882.         }
  883.         return [
  884.             'threads' => $threadCollection,
  885.             'pagination' => $paginationData,
  886.         ];
  887.     }
  888.     public function massXhrUpdate(Request $request)
  889.     {
  890.         $params $request->request->get('data');
  891.         foreach ($params['ids'] as $ticketId) {
  892.             $ticket $this->entityManager->getRepository(Ticket::class)->find($ticketId);
  893.             if (false == $this->isTicketAccessGranted($ticket)) {
  894.                 throw new \Exception('Access Denied'403);
  895.             }
  896.             
  897.             if (empty($ticket)) {
  898.                 continue;
  899.             }
  900.             switch ($params['actionType']) {
  901.                 case 'trashed':
  902.                     if (false == $ticket->getIsTrashed()) {
  903.                         $ticket->setIsTrashed(true);
  904.                         
  905.                         $this->entityManager->persist($ticket);
  906.                     }
  907.                     // Trigger ticket delete event
  908.                     $event = new GenericEvent(CoreWorkflowEvents\Ticket\Delete::getId(), [
  909.                         'entity' => $ticket,
  910.                     ]);
  911.                     $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  912.                     break;
  913.                 case 'delete':
  914.                     $threads $ticket->getThreads();
  915.                     $fileService = new Filesystem();
  916.                     if (count($threads) > 0) {
  917.                         foreach($threads as $thread) {
  918.                             if (!empty($thread)) {
  919.                                 $fileService->remove($this->container->getParameter('kernel.project_dir').'/public/assets/threads/'.$thread->getId());
  920.                             }
  921.                         }
  922.                     }
  923.                     $this->entityManager->remove($ticket);
  924.                     
  925.                     break;
  926.                 case 'restored':
  927.                     if (true == $ticket->getIsTrashed()) {
  928.                         $ticket->setIsTrashed(false);
  929.                         $this->entityManager->persist($ticket);
  930.                     }
  931.                     break;
  932.                 case 'agent':
  933.                     if ($ticket->getAgent() == null || $ticket->getAgent() && $ticket->getAgent()->getId() != $params['targetId']) {
  934.                         $agent $this->entityManager->getRepository(User::class)->find($params['targetId']);
  935.                         $ticket->setAgent($agent);
  936.     
  937.                         $this->entityManager->persist($ticket);
  938.     
  939.                         // Trigger Agent Assign event
  940.                         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Agent::getId(), [
  941.                             'entity' => $ticket,
  942.                             'customfields' => "",
  943.                         ]);
  944.     
  945.                         $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  946.                     }
  947.                     break;
  948.                 case 'status':
  949.                     if ($ticket->getStatus() == null || $ticket->getStatus() && $ticket->getStatus()->getId() != $params['targetId']) {
  950.                         $status $this->entityManager->getRepository(TicketStatus::class)->findOneById($params['targetId']);
  951.                         $ticket->setStatus($status);
  952.                         $this->entityManager->persist($ticket);
  953.                         // Trigger ticket status event
  954.                         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Status::getId(), [
  955.                             'entity' => $ticket,
  956.                         ]);
  957.                         
  958.                         $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  959.                     }
  960.                     
  961.                     break;
  962.                 case 'type':
  963.                     if ($ticket->getType() == null || $ticket->getType() && $ticket->getType()->getId() != $params['targetId']) {
  964.                         $type $this->entityManager->getRepository(TicketType::class)->findOneById($params['targetId']);
  965.                         $ticket->setType($type);
  966.     
  967.                         $this->entityManager->persist($ticket);
  968.     
  969.                         // Trigger ticket type event
  970.                         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Type::getId(), [
  971.                             'entity' => $ticket,
  972.                         ]);
  973.     
  974.                         $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  975.                     }
  976.                     break;
  977.                 case 'group':
  978.                     if ($ticket->getSupportGroup() == null || $ticket->getSupportGroup() && $ticket->getSupportGroup()->getId() != $params['targetId']) {
  979.                         $group $this->entityManager->getRepository(SupportGroup::class)->find($params['targetId']);
  980.                         $ticket->setSupportGroup($group);
  981.     
  982.                         $this->entityManager->persist($ticket);
  983.     
  984.                         // Trigger Support group event
  985.                         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Group::getId(), [
  986.                             'entity' => $ticket,
  987.                         ]);
  988.     
  989.                         $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  990.                     }
  991.                     break;
  992.                 case 'team':
  993.                     if ($ticket->getSupportTeam() == null || $ticket->getSupportTeam() && $ticket->getSupportTeam()->getId() != $params['targetId']){
  994.                         $team $this->entityManager->getRepository(SupportTeam::class)->find($params['targetId']);
  995.                         $ticket->setSupportTeam($team);
  996.                         
  997.                         $this->entityManager->persist($ticket);
  998.         
  999.                         // Trigger team event
  1000.                         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Team::getId(), [
  1001.                             'entity' => $ticket,
  1002.                         ]);
  1003.         
  1004.                         $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  1005.                     }
  1006.                     break;
  1007.                 case 'priority':
  1008.                     if ($ticket->getPriority() == null || $ticket->getPriority() && $ticket->getPriority()->getId() != $params['targetId']) {
  1009.                         
  1010.                         $priority $this->entityManager->getRepository(TicketPriority::class)->find($params['targetId']);
  1011.                         $ticket->setPriority($priority);
  1012.     
  1013.                         $this->entityManager->persist($ticket);
  1014.     
  1015.                         // Trigger ticket Priority event
  1016.                         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Priority::getId(), [
  1017.                             'entity' => $ticket,
  1018.                         ]);
  1019.     
  1020.                         $this->container->get('event_dispatcher')->dispatch($event'uvdesk.automation.workflow.execute');
  1021.                     }
  1022.                     break;
  1023.                 case 'label':
  1024.                     $label $this->entityManager->getRepository(SupportLabel::class)->find($params['targetId']);
  1025.                     
  1026.                     if ($label && !$this->entityManager->getRepository(Ticket::class)->isLabelAlreadyAdded($ticket$label)) {
  1027.                         $ticket->addSupportLabel($label);
  1028.                     }
  1029.                     
  1030.                     $this->entityManager->persist($ticket);
  1031.                     break;
  1032.                 default:
  1033.                     break;
  1034.             }
  1035.         } 
  1036.         $this->entityManager->flush();
  1037.         return [
  1038.             'alertClass' => 'success',
  1039.             'alertMessage' => $this->trans('Tickets have been updated successfully'),
  1040.         ];
  1041.     }
  1042.     
  1043.     public function getNotePlaceholderValues($ticket$type "customer")
  1044.     {
  1045.         $variables = array();
  1046.         $variables['ticket.id'] = $ticket->getId();
  1047.         $variables['ticket.subject'] = $ticket->getSubject();
  1048.         $variables['ticket.status'] = $ticket->getStatus()->getCode();
  1049.         $variables['ticket.priority'] = $ticket->getPriority()->getCode();
  1050.         if($ticket->getSupportGroup())
  1051.             $variables['ticket.group'] = $ticket->getSupportGroup()->getName();
  1052.         else
  1053.             $variables['ticket.group'] = '';
  1054.         $variables['ticket.team'] = ($ticket->getSupportTeam() ? $ticket->getSupportTeam()->getName() : '');
  1055.         $customer $this->container->get('user.service')->getCustomerPartialDetailById($ticket->getCustomer()->getId());
  1056.         $variables['ticket.customerName'] = $customer['name'];
  1057.         $userService $this->container->get('user.service');
  1058.       
  1059.         $variables['ticket.agentName'] = '';
  1060.         $variables['ticket.agentEmail'] = '';
  1061.         if ($ticket->getAgent()) {
  1062.             $agent $this->container->get('user.service')->getAgentDetailById($ticket->getAgent()->getId());
  1063.             if($agent) {
  1064.                 $variables['ticket.agentName'] = $agent['name'];
  1065.                 $variables['ticket.agentEmail'] = $agent['email'];
  1066.             }
  1067.         }
  1068.         $router $this->container->get('router');
  1069.         if ($type == 'customer') {
  1070.             $ticketListURL $router->generate('helpdesk_member_ticket_collection', [
  1071.                 'id' => $ticket->getId(),
  1072.             ], UrlGeneratorInterface::ABSOLUTE_URL);
  1073.         } else {
  1074.             $ticketListURL $router->generate('helpdesk_customer_ticket_collection', [
  1075.                 'id' => $ticket->getId(),
  1076.             ], UrlGeneratorInterface::ABSOLUTE_URL);
  1077.         }
  1078.         $variables['ticket.link'] = sprintf("<a href='%s'>#%s</a>"$ticketListURL$ticket->getId());
  1079.         return $variables;
  1080.     }
  1081.     public function paginateMembersTicketTypeCollection(Request $request)
  1082.     {
  1083.         // Get base query
  1084.         $params $request->query->all();
  1085.         $ticketRepository $this->entityManager->getRepository(Ticket::class);
  1086.         $paginationQuery $ticketRepository->prepareBasePaginationTicketTypesQuery($params);
  1087.         // Apply Pagination
  1088.         $paginationOptions = ['distinct' => true];
  1089.         $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  1090.         $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $ticketRepository::DEFAULT_PAGINATION_LIMIT;
  1091.         $pagination $this->container->get('knp_paginator')->paginate($paginationQuery$pageNumber$itemsLimit$paginationOptions);
  1092.         // Process Pagination Response
  1093.         $paginationParams $pagination->getParams();
  1094.         $paginationData $pagination->getPaginationData();
  1095.         $paginationParams['page'] = 'replacePage';
  1096.         $paginationData['url'] = '#' $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  1097.         return [
  1098.             'types' => array_map(function ($ticketType) {
  1099.                 return [
  1100.                     'id' => $ticketType->getId(),
  1101.                     'code' => strtoupper($ticketType->getCode()),
  1102.                     'description' => $ticketType->getDescription(),
  1103.                     'isActive' => $ticketType->getIsActive(),
  1104.                 ];
  1105.             }, $pagination->getItems()),
  1106.             'pagination_data' => $paginationData,
  1107.         ];
  1108.     }
  1109.     public function paginateMembersTagCollection(Request $request)
  1110.     {
  1111.         // Get base query
  1112.         $params $request->query->all();
  1113.         $ticketRepository $this->entityManager->getRepository(Ticket::class);
  1114.         $baseQuery $ticketRepository->prepareBasePaginationTagsQuery($params);
  1115.         // Apply Pagination
  1116.         $paginationResultsQuery = clone $baseQuery;
  1117.         $paginationResultsQuery->select('COUNT(supportTag.id)');
  1118.         $paginationQuery $baseQuery->getQuery()->setHydrationMode(Query::HYDRATE_ARRAY)->setHint('knp_paginator.count'count($paginationResultsQuery->getQuery()->getResult()));
  1119.         $paginationOptions = ['distinct' => true];
  1120.         $pageNumber = !empty($params['page']) ? (int) $params['page'] : 1;
  1121.         $itemsLimit = !empty($params['limit']) ? (int) $params['limit'] : $ticketRepository::DEFAULT_PAGINATION_LIMIT;
  1122.         $pagination $this->container->get('knp_paginator')->paginate($paginationQuery$pageNumber$itemsLimit$paginationOptions);
  1123.         // Process Pagination Response
  1124.         $paginationParams $pagination->getParams();
  1125.         $paginationData $pagination->getPaginationData();
  1126.         $paginationParams['page'] = 'replacePage';
  1127.         $paginationData['url'] = '#' $this->container->get('uvdesk.service')->buildPaginationQuery($paginationParams);
  1128.         if (in_array('UVDeskSupportCenterBundle'array_keys($this->container->getParameter('kernel.bundles')))) {
  1129.             $articleRepository $this->entityManager->getRepository(Article::class);
  1130.             return [
  1131.                 'tags' => array_map(function ($supportTag) use ($articleRepository) {
  1132.                     return [
  1133.                         'id' => $supportTag['id'],
  1134.                         'name' => $supportTag['name'],
  1135.                         'ticketCount' => $supportTag['totalTickets'],
  1136.                         'articleCount' => $articleRepository->getTotalArticlesBySupportTag($supportTag['id']),
  1137.                     ];
  1138.                 }, $pagination->getItems()),
  1139.                 'pagination_data' => $paginationData,
  1140.             ];
  1141.         } else {
  1142.             return [
  1143.                 'tags' => array_map(function ($supportTag) {
  1144.                     return [
  1145.                         'id' => $supportTag['id'],
  1146.                         'name' => $supportTag['name'],
  1147.                         'ticketCount' => $supportTag['totalTickets'],
  1148.                     ];
  1149.                 }, $pagination->getItems()),
  1150.                 'pagination_data' => $paginationData,
  1151.             ];
  1152.         }
  1153.     }
  1154.     public function getTicketInitialThreadDetails(Ticket $ticket)
  1155.     {
  1156.         $initialThread $this->entityManager->getRepository(Thread::class)->findOneBy([
  1157.             'ticket' => $ticket,
  1158.             'threadType' => 'create',
  1159.         ]);
  1160.         $ticketId $initialThread->getTicket()->getId();
  1161.         $databaseUrl $_ENV['DATABASE_URL'] ?? getenv('DATABASE_URL');
  1162.         $parsedUrl parse_url($databaseUrl);
  1163.     
  1164.         $host $parsedUrl['host'];
  1165.         $db   ltrim($parsedUrl['path'], '/');
  1166.         $user $parsedUrl['user'];;
  1167.         $pass $parsedUrl['pass'];
  1168.         $charset 'utf8mb4';
  1169.         $dsn "mysql:host=$host;dbname=$db;charset=$charset";
  1170.         // 2. Options for PDO
  1171.         $options = [
  1172.             PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,  // throw exceptions on errors
  1173.             PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,        // fetch as associative array
  1174.             PDO::ATTR_EMULATE_PREPARES   => false,                   // use native prepared statements
  1175.         ];
  1176.         try {
  1177.             // 3. Create the PDO connection
  1178.             $connection = new PDO($dsn$user$pass$options);
  1179.         } catch (\PDOException $e) {
  1180.             // 4. Handle connection error
  1181.             throw new \PDOException($e->getMessage(), (int)$e->getCode());
  1182.         }
  1183.         // 1. Define the SQL with a parameter placeholder :ticketId
  1184.         $sql "
  1185.         SELECT custom_field_id, value
  1186.         FROM uv_pkg_uvdesk_form_component_ticket_custom_fields_values
  1187.         WHERE ticket_id = :ticketId
  1188.         AND thread_id IS NULL
  1189.         ";
  1190.         $stmt $connection->prepare($sql);
  1191.         $stmt->bindParam(':ticketId'$ticketIdPDO::PARAM_INT);
  1192.         $stmt->execute();
  1193.         $rows $stmt->fetchAll();
  1194.         // Optional: Transform into an array keyed by custom_field_id
  1195.         $customFieldValues = [];
  1196.         foreach ($rows as $row) {
  1197.             $customFieldValues[] = [
  1198.                 'custom_field_id' => $row['custom_field_id'],
  1199.                 'value'           => $row['value']
  1200.             ];
  1201.         }
  1202.         if (!empty($initialThread)) {
  1203.             $author $initialThread->getUser();
  1204.             $authorInstance 'agent' == $initialThread->getCreatedBy() ? $author->getAgentInstance() : $author->getCustomerInstance();
  1205.         
  1206.             $threadDetails = [
  1207.                 'id' => $initialThread->getId(),
  1208.                 'source' => $initialThread->getSource(),
  1209.                 'messageId' => $initialThread->getMessageId(),
  1210.                 'threadType' => $initialThread->getThreadType(),
  1211.                 'createdBy' => $initialThread->getCreatedBy(),
  1212.                 'message' => html_entity_decode($initialThread->getMessage()),
  1213.                 'attachments' => $initialThread->getAttachments(),
  1214.                 'timestamp' => $initialThread->getCreatedAt()->getTimestamp(),
  1215.                 'createdAt' => $initialThread->getCreatedAt()->format('d-m-Y h:ia'),
  1216.                 'user' => $authorInstance->getPartialDetails(),
  1217.                 'cc' => is_array($initialThread->getCc()) ? implode(', '$initialThread->getCc()) : '',
  1218.                 'customfieldsvalue' => $customFieldValues,
  1219.             ];
  1220.             $attachments $threadDetails['attachments']->getValues();
  1221.             if (!empty($attachments)) {
  1222.                 $uvdeskFileSystemService $this->container->get('uvdesk.core.file_system.service');
  1223.                 $threadDetails['attachments'] = array_map(function ($attachment) use ($uvdeskFileSystemService) {
  1224.                     return $uvdeskFileSystemService->getFileTypeAssociations($attachment);
  1225.                 }, $attachments);
  1226.             }
  1227.         }
  1228.         return $threadDetails ?? null;
  1229.     }
  1230.     public function getCreateReply($ticketId$firewall 'member')
  1231.     {
  1232.         $qb $this->entityManager->createQueryBuilder();
  1233.         $qb->select("th,a,u.id as userId")->from(Thread::class, 'th')
  1234.                 ->leftJoin('th.ticket','t')
  1235.                 ->leftJoin('th.attachments''a')
  1236.                 ->leftJoin('th.user','u')
  1237.                 ->andWhere('t.id = :ticketId')
  1238.                 ->andWhere('th.threadType = :threadType')
  1239.                 ->setParameter('threadType','create')
  1240.                 ->setParameter('ticketId',$ticketId)
  1241.                 ->orderBy('th.id''DESC')
  1242.                 ->getMaxResults(1);
  1243.         $threadResponse $qb->getQuery()->getArrayResult();
  1244.         if((!empty($threadResponse[0][0]))) {
  1245.             $threadDetails $threadResponse[0][0];
  1246.             $userService $this->container->get('user.service');
  1247.             
  1248.             if ($threadDetails['createdBy'] == 'agent') {
  1249.                 $threadDetails['user'] = $userService->getAgentDetailById($threadResponse[0]['userId']);
  1250.             } else {
  1251.                 $threadDetails['user'] = $userService->getCustomerPartialDetailById($threadResponse[0]['userId']);
  1252.             }
  1253.             
  1254.             $threadDetails['reply'] = html_entity_decode($threadDetails['message']);
  1255.             $threadDetails['formatedCreatedAt'] = $this->timeZoneConverter($threadDetails['createdAt']);    
  1256.             $threadDetails['timestamp'] = $userService->convertToDatetimeTimezoneTimestamp($threadDetails['createdAt']);
  1257.         
  1258.             if (!empty($threadDetails['attachments'])) {
  1259.                 $entityManager $this->entityManager;
  1260.                 $uvdeskFileSystemService $this->container->get('uvdesk.core.file_system.service');
  1261.                 $threadDetails['attachments'] = array_map(function ($attachment) use ($entityManager$uvdeskFileSystemService$firewall) {
  1262.                     $attachmentReferenceObject $entityManager->getReference(Attachment::class, $attachment['id']);
  1263.                     return $uvdeskFileSystemService->getFileTypeAssociations($attachmentReferenceObject$firewall);
  1264.                 }, $threadDetails['attachments']);
  1265.             }
  1266.         }
  1267.         
  1268.         return $threadDetails ?? null;
  1269.     }
  1270.     public function hasAttachments($ticketId) {
  1271.         $qb $this->entityManager->createQueryBuilder();
  1272.         $qb->select("DISTINCT COUNT(a.id) as attachmentCount")->from(Thread::class, 'th')
  1273.                 ->leftJoin('th.ticket','t')
  1274.                 ->leftJoin('th.attachments','a')
  1275.                 ->andWhere('t.id = :ticketId')
  1276.                 ->setParameter('ticketId',$ticketId);
  1277.         return intval($qb->getQuery()->getSingleScalarResult());
  1278.     }
  1279.     public function getAgentDraftReply()
  1280.     {
  1281.         $signature $this->getUser()->getAgentInstance()->getSignature();
  1282.         
  1283.         return str_replace"\n"'<br/>'$signature);
  1284.     }
  1285.     public function trans($text)
  1286.     {
  1287.         return $this->container->get('translator')->trans($text);
  1288.     }
  1289.     public function getAllSources()
  1290.     {
  1291.         $sources = ['email' => 'Email''website' => 'Website'];
  1292.         return $sources;
  1293.     }
  1294.     public function getCustomLabelDetails($container)
  1295.     {
  1296.         $currentUser $container->get('user.service')->getCurrentUser();
  1297.         $qb $this->entityManager->createQueryBuilder();
  1298.         $qb->select('COUNT(DISTINCT t) as ticketCount,sl.id')->from(Ticket::class, 't')
  1299.                 ->leftJoin('t.supportLabels','sl')
  1300.                 ->andwhere('sl.user = :userId')
  1301.                 ->setParameter('userId'$currentUser->getId())
  1302.                 ->groupBy('sl.id');
  1303.         $ticketCountResult $qb->getQuery()->getResult();
  1304.         $data = array();
  1305.         $qb $this->entityManager->createQueryBuilder();
  1306.         $qb->select('sl.id,sl.name,sl.colorCode')->from(SupportLabel::class, 'sl')
  1307.                 ->andwhere('sl.user = :userId')
  1308.                 ->setParameter('userId'$currentUser->getId());
  1309.         $labels $qb->getQuery()->getResult();
  1310.         foreach ($labels as $key => $label) {
  1311.             $labels[$key]['count'] = 0;
  1312.             foreach ($ticketCountResult as $ticketCount) {
  1313.                 if(($label['id'] == $ticketCount['id']))
  1314.                     $labels[$key]['count'] = $ticketCount['ticketCount'] ?: 0;
  1315.             }
  1316.         }
  1317.         return $labels;
  1318.     }
  1319.     public function getLabels($request null)
  1320.     {
  1321.         static $labels;
  1322.         if (null !== $labels)
  1323.             return $labels;
  1324.         $qb $this->entityManager->createQueryBuilder();
  1325.         $qb->select('sl')->from(SupportLabel::class, 'sl')
  1326.             ->andwhere('sl.user = :userId')
  1327.             ->setParameter('userId'$this->getUser()->getId());
  1328.         if($request) {
  1329.             $qb->andwhere("sl.name LIKE :labelName");
  1330.             $qb->setParameter('labelName''%'.urldecode($request->query->get('query')).'%');
  1331.         }
  1332.         return $labels $qb->getQuery()->getArrayResult();
  1333.     }
  1334.     public function getTicketCollaborators($ticketId)
  1335.     {
  1336.         $qb $this->entityManager->createQueryBuilder();
  1337.         $qb->select("DISTINCT c.id, c.email, CONCAT(c.firstName,' ', c.lastName) AS name, userInstance.profileImagePath, userInstance.profileImagePath as smallThumbnail")->from(Ticket::class, 't')
  1338.                 ->leftJoin('t.collaborators''c')
  1339.                 ->leftJoin('c.userInstance''userInstance')
  1340.                 ->andwhere('t.id = :ticketId')
  1341.                 ->andwhere('userInstance.supportRole = :roles')
  1342.                 ->setParameter('ticketId'$ticketId)
  1343.                 ->setParameter('roles'4)
  1344.                 ->orderBy('name','ASC');
  1345.         return $qb->getQuery()->getArrayResult();
  1346.     }
  1347.     public function getTicketTagsById($ticketId)
  1348.     {
  1349.         $qb $this->entityManager->createQueryBuilder();
  1350.         $qb->select('tg')->from(Tag::class, 'tg')
  1351.                 ->leftJoin('tg.tickets' ,'t')
  1352.                 ->andwhere('t.id = :ticketId')
  1353.                 ->setParameter('ticketId'$ticketId);
  1354.         return $qb->getQuery()->getArrayResult();
  1355.     }
  1356.     public function getTicketLabels($ticketId)
  1357.     {
  1358.         $qb $this->entityManager->createQueryBuilder();
  1359.         $qb->select('DISTINCT sl.id,sl.name,sl.colorCode')->from(Ticket::class, 't')
  1360.                 ->leftJoin('t.supportLabels','sl')
  1361.                 ->leftJoin('sl.user','slu')
  1362.                 ->andWhere('slu.id = :userId')
  1363.                 ->andWhere('t.id = :ticketId')
  1364.                 ->setParameter('userId'$this->getUser()->getId())
  1365.                 ->setParameter('ticketId'$ticketId);
  1366.         $result $qb->getQuery()->getResult();
  1367.         
  1368.         return $result $result : [];
  1369.     }
  1370.     public function getUserLabels()
  1371.     {
  1372.         $qb $this->entityManager->createQueryBuilder();
  1373.         $qb->select('sl')->from(SupportLabel::class, 'sl')
  1374.                 ->leftJoin('sl.user','slu')
  1375.                 ->andWhere('slu.id = :userId')
  1376.                 ->setParameter('userId'$this->getUser()->getId());
  1377.         $result $qb->getQuery()->getResult();
  1378.         
  1379.         return $result $result : [];
  1380.     }
  1381.     public function getTicketLabelsAll($ticketId)
  1382.     {
  1383.         $qb $this->entityManager->createQueryBuilder();
  1384.         $qb->select('DISTINCT sl.id,sl.name,sl.colorCode')->from(Ticket::class, 't')
  1385.                 ->leftJoin('t.supportLabels','sl')
  1386.                 ->andWhere('t.id = :ticketId')
  1387.                 ->setParameter('ticketId'$ticketId);
  1388.         $result $qb->getQuery()->getResult();
  1389.         
  1390.         return $result $result : [];
  1391.     }
  1392.     public function getManualWorkflow()
  1393.     {
  1394.         $preparedResponseIds = [];
  1395.         $groupIds = [];
  1396.         $teamIds = []; 
  1397.         $userId $this->container->get('user.service')->getCurrentUser()->getAgentInstance()->getId();
  1398.         $preparedResponseRepo $this->entityManager->getRepository(PreparedResponses::class)->findAll();
  1399.         foreach ($preparedResponseRepo as $pr) {
  1400.             if ($userId == $pr->getUser()->getId()) {
  1401.                 //Save the ids of the saved reply.
  1402.                 array_push($preparedResponseIds, (int)$pr->getId());
  1403.             }
  1404.         }
  1405.         // Get the ids of the Group(s) the current user is associated with.
  1406.         $query "select * from uv_user_support_groups where userInstanceId =".$userId;
  1407.         $connection $this->entityManager->getConnection();
  1408.         $stmt $connection->prepare($query);
  1409.         $stmt->execute();
  1410.         $result $stmt->fetchAll();
  1411.         foreach ($result as $row) {
  1412.             array_push($groupIds$row['supportGroupId']);
  1413.         }
  1414.         // Get all the saved reply's ids that is associated with the user's group(s).
  1415.         $query "select * from uv_prepared_response_support_groups";
  1416.         $stmt $connection->prepare($query);
  1417.         $stmt->execute();
  1418.         $result $stmt->fetchAll();
  1419.         foreach ($result as $row) {
  1420.             if (in_array($row['group_id'], $groupIds)) {
  1421.                 array_push($preparedResponseIds, (int) $row['savedReply_id']);
  1422.             }
  1423.         }
  1424.         // Get the ids of the Team(s) the current user is associated with.
  1425.         $query "select * from uv_user_support_teams";
  1426.         $connection $this->entityManager->getConnection();
  1427.         $stmt $connection->prepare($query);
  1428.         $stmt->execute();
  1429.         $result $stmt->fetchAll();
  1430.         foreach($result as $row) {
  1431.             if ($row['userInstanceId'] == $userId) {
  1432.                 array_push($teamIds$row['supportTeamId']);
  1433.             }
  1434.         }
  1435.         $query "select * from uv_prepared_response_support_teams";
  1436.         $stmt $connection->prepare($query);
  1437.         $stmt->execute();
  1438.         $result $stmt->fetchAll();
  1439.         foreach ($result as $row) {
  1440.             if (in_array($row['subgroup_id'], $teamIds)) {
  1441.                 array_push($preparedResponseIds, (int)$row['savedReply_id']);
  1442.             }
  1443.         }
  1444.         $qb $this->entityManager->createQueryBuilder();
  1445.         $qb->select('DISTINCT mw')
  1446.             ->from(PreparedResponses::class, 'mw')
  1447.             ->where('mw.status = 1')
  1448.             ->andWhere('mw.id IN (:ids)')
  1449.             ->setParameter('ids'$preparedResponseIds);
  1450.         
  1451.         return $qb->getQuery()->getResult();
  1452.     }
  1453.     public function getSavedReplies()
  1454.     {   
  1455.         $savedReplyIds = [];
  1456.         $groupIds = [];
  1457.         $teamIds = []; 
  1458.         $userId $this->container->get('user.service')->getCurrentUser()->getAgentInstance()->getId();
  1459.         $savedReplyRepo $this->entityManager->getRepository(SavedReplies::class)->findAll();
  1460.         foreach ($savedReplyRepo as $sr) {
  1461.             if ($userId == $sr->getUser()->getId()) {
  1462.                 //Save the ids of the saved reply.
  1463.                 array_push($savedReplyIds, (int)$sr->getId());
  1464.             }
  1465.         }
  1466.         // Get the ids of the Group(s) the current user is associated with.
  1467.         $query "select * from uv_user_support_groups where userInstanceId =".$userId;
  1468.         $connection $this->entityManager->getConnection();
  1469.         $stmt $connection->prepare($query);
  1470.         $stmt->execute();
  1471.         $result $stmt->fetchAll();
  1472.         foreach ($result as $row) {
  1473.             array_push($groupIds$row['supportGroupId']);
  1474.         }
  1475.         // Get all the saved reply's ids that is associated with the user's group(s).
  1476.         $query "select * from uv_saved_replies_groups";
  1477.         $stmt $connection->prepare($query);
  1478.         $stmt->execute();
  1479.         $result $stmt->fetchAll();
  1480.         foreach ($result as $row) {
  1481.             if (in_array($row['group_id'], $groupIds)) {
  1482.                 array_push($savedReplyIds, (int) $row['savedReply_id']);
  1483.             }
  1484.         }
  1485.         // Get the ids of the Team(s) the current user is associated with.
  1486.         $query "select * from uv_user_support_teams";
  1487.         $connection $this->entityManager->getConnection();
  1488.         $stmt $connection->prepare($query);
  1489.         $stmt->execute();
  1490.         $result $stmt->fetchAll();
  1491.         foreach($result as $row) {
  1492.             if ($row['userInstanceId'] == $userId) {
  1493.                 array_push($teamIds$row['supportTeamId']);
  1494.             }
  1495.         }
  1496.         $query "select * from uv_saved_replies_teams";
  1497.         $stmt $connection->prepare($query);
  1498.         $stmt->execute();
  1499.         $result $stmt->fetchAll();
  1500.         foreach ($result as $row) {
  1501.             if (in_array($row['subgroup_id'], $teamIds)) {
  1502.                 array_push($savedReplyIds, (int)$row['savedReply_id']);
  1503.             }
  1504.         }
  1505.         $qb $this->entityManager->createQueryBuilder();
  1506.         $qb->select('DISTINCT sr')
  1507.         ->from(SavedReplies::class, 'sr')
  1508.         ->Where('sr.id IN (:ids)')
  1509.         ->setParameter('ids'$savedReplyIds);
  1510.         
  1511.         return $qb->getQuery()->getResult();
  1512.     }
  1513.     public function getPriorities()
  1514.     {
  1515.         static $priorities;
  1516.         if (null !== $priorities)
  1517.             return $priorities;
  1518.         $qb $this->entityManager->createQueryBuilder();
  1519.         $qb->select('tp')->from(TicketPriority::class, 'tp');
  1520.         return $priorities $qb->getQuery()->getArrayResult();
  1521.     }
  1522.     public function getTicketLastThread($ticketId)
  1523.     {
  1524.         $qb $this->entityManager->createQueryBuilder();
  1525.         $qb->select("th")->from(Thread::class, 'th')
  1526.                 ->leftJoin('th.ticket','t')
  1527.                 ->andWhere('t.id = :ticketId')
  1528.                 ->setParameter('ticketId',$ticketId)
  1529.                 ->orderBy('th.id''DESC');
  1530.         return $qb->getQuery()->setMaxResults(1)->getSingleResult();
  1531.     }
  1532.     public function getlastReplyAgentName($ticketId)
  1533.     {
  1534.         $qb $this->entityManager->createQueryBuilder();
  1535.         $qb->select("u.id,CONCAT(u.firstName,' ', u.lastName) AS name,u.firstName")->from(Thread::class, 'th')
  1536.                 ->leftJoin('th.ticket','t')
  1537.                 ->leftJoin('th.user''u')
  1538.                 ->leftJoin('u.userInstance''userInstance')
  1539.                 ->andwhere('userInstance.supportRole != :roles')
  1540.                 ->andWhere('t.id = :ticketId')
  1541.                 ->andWhere('th.threadType = :threadType')
  1542.                 ->setParameter('threadType','reply')
  1543.                 ->andWhere('th.createdBy = :createdBy')
  1544.                 ->setParameter('createdBy','agent')
  1545.                 ->setParameter('ticketId',$ticketId)
  1546.                 ->setParameter('roles'4)
  1547.                 ->orderBy('th.id''DESC');
  1548.         $result $qb->getQuery()->setMaxResults(1)->getResult();
  1549.         return $result $result[0] : null;
  1550.     }
  1551.     public function getLastReply($ticketId$userType null
  1552.     {
  1553.         $queryBuilder $this->entityManager->createQueryBuilder();
  1554.         $queryBuilder->select("th, a, u.id as userId")
  1555.             ->from(Thread::class, 'th')
  1556.             ->leftJoin('th.ticket','t')
  1557.             ->leftJoin('th.attachments''a')
  1558.             ->leftJoin('th.user','u')
  1559.             ->andWhere('t.id = :ticketId')
  1560.             ->andWhere('th.threadType = :threadType')
  1561.             ->setParameter('threadType','reply')
  1562.             ->setParameter('ticketId',$ticketId)
  1563.             ->orderBy('th.id''DESC')
  1564.             ->getMaxResults(1);
  1565.         if (!empty($userType)) {
  1566.             $queryBuilder->andWhere('th.createdBy = :createdBy')->setParameter('createdBy'$userType);
  1567.         }
  1568.         
  1569.         $threadResponse $queryBuilder->getQuery()->getArrayResult();
  1570.         
  1571.         if (!empty($threadResponse[0][0])) {
  1572.             $threadDetails $threadResponse[0][0];
  1573.             $userService $this->container->get('user.service');
  1574.             
  1575.             if ($threadDetails['createdBy'] == 'agent') {
  1576.                 $threadDetails['user'] = $userService->getAgentDetailById($threadResponse[0]['userId']);
  1577.             } else {
  1578.                 $threadDetails['user'] = $userService->getCustomerPartialDetailById($threadResponse[0]['userId']);
  1579.             }
  1580.             
  1581.             $threadDetails['reply'] = html_entity_decode($threadDetails['message']);
  1582.             $threadDetails['formatedCreatedAt'] = $this->timeZoneConverter($threadDetails['createdAt']);
  1583.             $threadDetails['timestamp'] = $userService->convertToDatetimeTimezoneTimestamp($threadDetails['createdAt']);
  1584.             if (!empty($threadDetails['attachments'])) {
  1585.                 $entityManager $this->entityManager;
  1586.                 $uvdeskFileSystemService $this->container->get('uvdesk.core.file_system.service');
  1587.                 $threadDetails['attachments'] = array_map(function ($attachment) use ($entityManager$uvdeskFileSystemService) {
  1588.                     $attachmentReferenceObject $this->entityManager->getReference(Attachment::class, $attachment['id']);
  1589.                     return $uvdeskFileSystemService->getFileTypeAssociations($attachmentReferenceObject);
  1590.                 }, $threadDetails['attachments']);
  1591.             }
  1592.         }
  1593.         return $threadDetails ?? null;
  1594.     }
  1595.     public function getSavedReplyContent($savedReplyId$ticketId)
  1596.     {
  1597.         $ticket $this->entityManager->getRepository(Ticket::class)->find($ticketId);
  1598.         $savedReply $this->entityManager->getRepository(SavedReplies::class)->findOneById($savedReplyId);
  1599.         $emailPlaceholders $this->getSavedReplyPlaceholderValues($ticket'customer');
  1600.         return $this->container->get('email.service')->processEmailContent($savedReply->getMessage(), $emailPlaceholderstrue);
  1601.     }
  1602.     public function getSavedReplyPlaceholderValues($ticket$type "customer")
  1603.     {
  1604.         $variables = array();
  1605.         $variables['ticket.id'] = $ticket->getId();
  1606.         $variables['ticket.subject'] = $ticket->getSubject();
  1607.         $variables['ticket.status'] = $ticket->getStatus()->getCode();
  1608.         $variables['ticket.priority'] = $ticket->getPriority()->getCode();
  1609.         if($ticket->getSupportGroup())
  1610.             $variables['ticket.group'] = $ticket->getSupportGroup()->getName();
  1611.         else
  1612.             $variables['ticket.group'] = '';
  1613.         $variables['ticket.team'] = ($ticket->getSupportTeam() ? $ticket->getSupportTeam()->getName() : '');
  1614.         $customer $this->container->get('user.service')->getCustomerPartialDetailById($ticket->getCustomer()->getId());
  1615.         $variables['ticket.customerName'] = $customer['name'];
  1616.         $variables['ticket.customerEmail'] = $customer['email'];
  1617.         $userService $this->container->get('user.service');
  1618.       
  1619.         $variables['ticket.agentName'] = '';
  1620.         $variables['ticket.agentEmail'] = '';
  1621.         if ($ticket->getAgent()) {
  1622.             $agent $this->container->get('user.service')->getAgentDetailById($ticket->getAgent()->getId());
  1623.             if($agent) {
  1624.                 $variables['ticket.agentName'] = $agent['name'];
  1625.                 $variables['ticket.agentEmail'] = $agent['email'];
  1626.             }
  1627.         }
  1628.         
  1629.         $router $this->container->get('router');
  1630.         if ($type == 'customer') {
  1631.             $ticketListURL $router->generate('helpdesk_customer_ticket_collection', [
  1632.                 'id' => $ticket->getId(),
  1633.             ], UrlGeneratorInterface::ABSOLUTE_URL);
  1634.         } else {
  1635.             $ticketListURL $router->generate('helpdesk_member_ticket_collection', [
  1636.                 'id' => $ticket->getId(),
  1637.             ], UrlGeneratorInterface::ABSOLUTE_URL);
  1638.         }
  1639.         $variables['ticket.link'] = sprintf("<a href='%s'>#%s</a>"$ticketListURL$ticket->getId());
  1640.         return $variables;
  1641.     }
  1642.     public function isEmailBlocked($email$website
  1643.     {
  1644.         $flag false;
  1645.         $email strtolower($email);
  1646.         $knowlegeBaseWebsite $this->entityManager->getRepository(KnowledgebaseWebsite::class)->findOneBy(['website' => $website->getId(), 'isActive' => 1]);
  1647.         $list $this->container->get('user.service')->getWebsiteSpamDetails($knowlegeBaseWebsite);
  1648.         // Blacklist
  1649.         if (!empty($list['blackList']['email']) && in_array($email$list['blackList']['email'])) {
  1650.             // Emails
  1651.             $flag true;
  1652.         } elseif (!empty($list['blackList']['domain'])) {
  1653.             // Domains
  1654.             foreach ($list['blackList']['domain'] as $domain) {
  1655.                 if (strpos($email$domain)) {
  1656.                     $flag true;
  1657.                     break;
  1658.                 }
  1659.             }
  1660.         }
  1661.         // Whitelist
  1662.         if ($flag) {
  1663.             if (isset($email$list['whiteList']['email']) && in_array($email$list['whiteList']['email'])) {
  1664.                 // Emails
  1665.                 return false;
  1666.             } elseif (isset($list['whiteList']['domain'])) {
  1667.                 // Domains
  1668.                 foreach ($list['whiteList']['domain'] as $domain) {
  1669.                     if (strpos($email$domain)) {
  1670.                         $flag false;
  1671.                     }
  1672.                 }
  1673.             }
  1674.         }
  1675.         return $flag;
  1676.     }
  1677.     public function timeZoneConverter($dateFlag)
  1678.     {
  1679.         $website $this->entityManager->getRepository(Website::class)->findOneBy(['code' => 'Knowledgebase']);
  1680.         $timeZone $website->getTimezone();
  1681.         $timeFormat $website->getTimeformat();
  1682.         $activeUser $this->container->get('user.service')->getSessionUser();
  1683.         $agentTimeZone = !empty($activeUser) ? $activeUser->getTimezone() : null;
  1684.         $agentTimeFormat = !empty($activeUser) ? $activeUser->getTimeformat() : null;
  1685.         $parameterType gettype($dateFlag);
  1686.         if($parameterType == 'string'){
  1687.             if(is_null($agentTimeZone) && is_null($agentTimeFormat)){
  1688.                 if(is_null($timeZone) && is_null($timeFormat)){
  1689.                     $datePattern date_create($dateFlag);
  1690.                     return date_format($datePattern,'d-m-Y h:ia');
  1691.                 } else {
  1692.                     $dateFlag = new \DateTime($dateFlag);
  1693.                     $datePattern $dateFlag->setTimezone(new \DateTimeZone($timeZone));
  1694.                     return date_format($datePattern$timeFormat);
  1695.                 }
  1696.             } else {
  1697.                 $dateFlag = new \DateTime($dateFlag);
  1698.                 $datePattern $dateFlag->setTimezone(new \DateTimeZone($agentTimeZone));
  1699.                 return date_format($datePattern$agentTimeFormat);
  1700.             }          
  1701.         } else {
  1702.             if(is_null($agentTimeZone) && is_null($agentTimeFormat)){
  1703.                 if(is_null($timeZone) && is_null($timeFormat)){
  1704.                     return date_format($dateFlag,'d-m-Y h:ia');
  1705.                 } else {
  1706.                     $datePattern $dateFlag->setTimezone(new \DateTimeZone($timeZone));
  1707.                     return date_format($datePattern$timeFormat);
  1708.                 }
  1709.             } else {
  1710.                 $datePattern $dateFlag->setTimezone(new \DateTimeZone($agentTimeZone));
  1711.                 return date_format($datePattern$agentTimeFormat);
  1712.             }    
  1713.         }         
  1714.     }
  1715.     public function fomatTimeByPreference($dbTime,$timeZone,$timeFormat,$agentTimeZone,$agentTimeFormat)
  1716.     {
  1717.         if(is_null($agentTimeZone) && is_null($agentTimeFormat)) {
  1718.             if(is_null($timeZone) && is_null($timeFormat)){
  1719.                 $dateTimeZone $dbTime;
  1720.                 $timeFormatString 'd-m-Y h:ia';
  1721.             } else {
  1722.                 $dateTimeZone $dbTime->setTimezone(new \DateTimeZone($timeZone));
  1723.                 $timeFormatString $timeFormat;
  1724.             }
  1725.         } else {
  1726.             $dateTimeZone $dbTime->setTimezone(new \DateTimeZone($agentTimeZone));
  1727.             $timeFormatString $agentTimeFormat;
  1728.         }
  1729.         $time['dateTimeZone'] = $dateTimeZone;
  1730.         $time['timeFormatString'] = $timeFormatString;
  1731.         return $time;
  1732.     }
  1733.     
  1734.     public function isTicketAccessGranted(Ticket $ticketUser $user null$firewall 'members')
  1735.     {
  1736.         // @TODO: Take current firewall into consideration (access check on behalf of agent/customer)
  1737.         if (empty($user)) {
  1738.             $user $this->container->get('user.service')->getSessionUser();
  1739.         }
  1740.         if (empty($user)) {
  1741.             return false;
  1742.         } else {
  1743.             $agentInstance $user->getAgentInstance();
  1744.     
  1745.             if (empty($agentInstance)) {
  1746.                 return false;
  1747.             }
  1748.         }
  1749.         if ($agentInstance->getSupportRole()->getId() == && in_array($agentInstance->getTicketAccessLevel(), [234])) {
  1750.             $accessLevel $agentInstance->getTicketAccessLevel();
  1751.             // Check if user has been given inidividual access
  1752.             if ($ticket->getAgent() != null && $ticket->getAgent()->getId() == $user->getId()) {
  1753.                 return true;
  1754.             }
  1755.             
  1756.             if ($accessLevel == || $accessLevel == 3) {
  1757.                 // Check if user belongs to a support team assigned to ticket
  1758.                 $teamReferenceIds array_map(function ($team) { return $team->getId(); }, $agentInstance->getSupportTeams()->toArray());
  1759.                 
  1760.                 if ($ticket->getSupportTeam() != null && in_array($ticket->getSupportTeam()->getId(), $teamReferenceIds)) {
  1761.                     return true;
  1762.                 } else if ($accessLevel == 2) {
  1763.                     // Check if user belongs to a support group assigned to ticket
  1764.                     $groupReferenceIds array_map(function ($group) { return $group->getId(); }, $agentInstance->getSupportGroups()->toArray());
  1765.                     if ($ticket->getSupportGroup() != null && in_array($ticket->getSupportGroup()->getId(), $groupReferenceIds)) {
  1766.                         return true;
  1767.                     }
  1768.                 }
  1769.             }
  1770.             return false;
  1771.         }
  1772.         return true;
  1773.     }
  1774.     public function addTicketCustomFields($thread$requestCustomFields = [], $filesCustomFields = [])
  1775.     {
  1776.         $ticket $thread->getTicket();
  1777.         $skipFileUpload false;
  1778.         $customFieldsCollection $this->entityManager->getRepository(CommunityPackageEntities\CustomFields::class)->findAll();
  1779.         foreach ($customFieldsCollection as $customFields) {
  1780.             if(in_array($customFields->getFieldType(), ['select''checkbox''radio']) && !count($customFields->getCustomFieldValues()))
  1781.                 continue;
  1782.             elseif('file' != $customFields->getFieldType() && $requestCustomFields && array_key_exists($customFields->getId(), $requestCustomFields) && $requestCustomFields[$customFields->getId()]) {
  1783.                 if(count($customFields->getCustomFieldsDependency()) && !in_array($ticket->getType(), $customFields->getCustomFieldsDependency()->toArray()))
  1784.                     continue;
  1785.                 $ticketCustomField = new CommunityPackageEntities\TicketCustomFieldsValues();
  1786.                 $ticketCustomField->setTicket($ticket);
  1787.                 //custom field
  1788.                 $ticketCustomField->setTicketCustomFieldsValues($customFields);
  1789.                 $ticketCustomField->setValue(json_encode($requestCustomFields[$customFields->getId()]));
  1790.                 if(in_array($customFields->getFieldType(), ['select''checkbox''radio'])) {
  1791.                     //add custom field values mapping too
  1792.                     if(is_array($requestCustomFields[$customFields->getId()])) {
  1793.                         foreach ($requestCustomFields[$customFields->getId()] as $value) {
  1794.                             if($ticketCustomFieldValues $this->entityManager->getRepository(CommunityPackageEntities\CustomFieldsValues::class)
  1795.                                 ->findOneBy(['customFields' => $customFields'id' => $value]))
  1796.                                 $ticketCustomField->setTicketCustomFieldValueValues($ticketCustomFieldValues);
  1797.                         }
  1798.                     } elseif($ticketCustomFieldValues $this->entityManager->getRepository(CommunityPackageEntities\CustomFieldsValues::class)
  1799.                             ->findOneBy(['customFields' => $customFields'id' => $requestCustomFields[$customFields->getId()]]))                                                        
  1800.                         $ticketCustomField->setTicketCustomFieldValueValues($ticketCustomFieldValues);
  1801.                 }
  1802.                 $this->entityManager->persist($ticketCustomField);
  1803.                 $this->entityManager->flush();
  1804.             } elseif($filesCustomFields && array_key_exists($customFields->getId(), $filesCustomFields) && $filesCustomFields[$customFields->getId()] && !$skipFileUpload) {
  1805.                 $skipFileUpload true;
  1806.                 //upload files
  1807.             
  1808.                 $path '/custom-fields/ticket/' $ticket->getId() . '/';
  1809.                 $fileNames $this->fileUploadService->uploadFile($filesCustomFields[$customFields->getid()], $pathtrue);
  1810.                 if(!empty($fileNames)) {
  1811.                     //save files entry to attachment table
  1812.                     try {
  1813.                         $customFieldsService null;
  1814.                         try {
  1815.                             if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  1816.                                 $customFieldsService $this->get('uvdesk_package_custom_fields.service');
  1817.                             } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  1818.                                 $customFieldsService $this->get('uvdesk_package_form_component.service');
  1819.                             }
  1820.                         } catch (\Exception $e) {
  1821.                             // @TODO: Log execption message
  1822.                         }
  1823.                         $newFilesNames = !empty($customFieldsService) ? $customFieldsService->addFilesEntryToAttachmentTable([$fileNames], $thread) : [];
  1824.                         foreach ($newFilesNames as $value) {
  1825.                             $ticketCustomField = new CommunityPackageEntities\TicketCustomFieldsValues();
  1826.                             $ticketCustomField->setTicket($ticket);
  1827.                             //custom field
  1828.                             $ticketCustomField->setTicketCustomFieldsValues($customFields);
  1829.                             $ticketCustomField->setValue(json_encode(['name' => $value['name'], 'path' => $value['path'], 'id' => $value['id']]));
  1830.                             $this->entityManager->persist($ticketCustomField);
  1831.                             $this->entityManager->flush();
  1832.                         }
  1833.                     } catch (\Exception $e) {
  1834.                         // @TODO: Log execption message
  1835.                     }
  1836.                 }
  1837.             }
  1838.         }
  1839.     }
  1840.     // return attachemnt for initial thread
  1841.     public function getInitialThread($ticketId)
  1842.     {
  1843.         $firstThread null;
  1844.         $intialThread $this->entityManager->getRepository(Thread::class)->findBy(['ticket'=>$ticketId]);
  1845.         foreach ($intialThread as $key => $value) {
  1846.             if($value->getThreadType() == "create"){
  1847.                 $firstThread $value;
  1848.             }
  1849.         }
  1850.         return $firstThread;
  1851.     }
  1852. }