vendor/uvdesk/core-framework/Controller/Ticket.php line 83

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\CoreFrameworkBundle\Controller;
  3. use Symfony\Component\HttpFoundation\Request;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\EventDispatcher\GenericEvent;
  6. use Webkul\UVDesk\CoreFrameworkBundle\Form as CoreFrameworkBundleForms;
  7. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  8. use Webkul\UVDesk\CoreFrameworkBundle\Entity as CoreFrameworkBundleEntities;
  9. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  10. use Webkul\UVDesk\CoreFrameworkBundle\DataProxies as CoreFrameworkBundleDataProxies;
  11. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  12. use Webkul\UVDesk\CoreFrameworkBundle\Tickets\QuickActionButtonCollection;
  13. use Webkul\UVDesk\CoreFrameworkBundle\Repository\TicketRepository;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  15. use Symfony\Contracts\Translation\TranslatorInterface;
  16. use Webkul\UVDesk\CoreFrameworkBundle\Services\UVDeskService;
  17. use Webkul\UVDesk\CoreFrameworkBundle\Services\TicketService;
  18. use Webkul\UVDesk\CoreFrameworkBundle\Services\EmailService;
  19. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  20. use Symfony\Component\HttpKernel\KernelInterface;
  21. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  22. use Symfony\Component\DependencyInjection\ContainerInterface;
  23. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Attachment;
  24. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Thread;
  25. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket as CoreBundleTicket;
  26. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Tag;
  27. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketType;
  28. use Webkul\UVDesk\CoreFrameworkBundle\Entity\SupportRole;
  29. use Webkul\UVDesk\CoreFrameworkBundle\Entity\User;
  30. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketPriority;
  31. use Webkul\UVDesk\CoreFrameworkBundle\Entity\TicketStatus;
  32. use Webkul\UVDesk\MailboxBundle\Services\MailboxService;
  33. class Ticket extends AbstractController
  34. {
  35.     private $userService;
  36.     private $translator;
  37.     private $eventDispatcher;
  38.     private $ticketService;
  39.     private $emailService;
  40.     private $kernel;
  41.     public function __construct(UserService $userServiceTranslatorInterface $translatorTicketService $ticketServiceEmailService $emailServiceEventDispatcherInterface $eventDispatcherKernelInterface $kernel)
  42.     {
  43.         $this->userService $userService;
  44.         $this->emailService $emailService;
  45.         $this->translator $translator;
  46.         $this->ticketService $ticketService;
  47.         $this->eventDispatcher $eventDispatcher;
  48.         $this->kernel $kernel;
  49.     }
  50.     public function listTicketCollection(Request $requestMailboxService $mailboxService)
  51.     {
  52.         $entityManager $this->getDoctrine()->getManager();
  53.         $mailboxCollection = [];
  54.         $mailboxConfiguration $mailboxService->parseMailboxConfigurations();
  55.         
  56.         foreach ($mailboxConfiguration->getMailboxes() as $mailbox) {
  57.             $imapConfiguration $mailbox->getImapConfiguration();
  58.             if (!empty($imapConfiguration)) {
  59.                 $mailboxCollection[] = [
  60.                     'name' => $mailbox->getName(), 
  61.                     'email' => $imapConfiguration->getUsername(), 
  62.                 ];
  63.             }
  64.         }
  65.         return $this->render('@UVDeskCoreFramework//ticketList.html.twig', [
  66.             'mailboxCollection' => $mailboxCollection
  67.             'ticketStatusCollection' => $entityManager->getRepository(TicketStatus::class)->findAll(), 
  68.             'ticketTypeCollection' => $entityManager->getRepository(TicketType::class)->findByIsActive(true), 
  69.             'ticketPriorityCollection' => $entityManager->getRepository(TicketPriority::class)->findAll(), 
  70.         ]);
  71.     }
  72.     public function loadTicket($ticketIdQuickActionButtonCollection $quickActionButtonCollectionContainerInterface $container)
  73.     {
  74.         $entityManager $this->getDoctrine()->getManager();
  75.         $userRepository $entityManager->getRepository(User::class);
  76.         $ticketRepository $entityManager->getRepository(CoreBundleTicket::class);
  77.         $ticket $ticketRepository->findOneById($ticketId);
  78.         
  79.         if (empty($ticket)) {
  80.             throw new NotFoundHttpException('Page not found!');
  81.         }
  82.         
  83.         $user $this->userService->getSessionUser();
  84.         
  85.         // Proceed only if user has access to the resource
  86.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  87.             throw new \Exception('Access Denied'403);
  88.         }
  89.         $agent $ticket->getAgent();
  90.         $customer $ticket->getCustomer();
  91.      
  92.     if($agent != null && !empty($agent)){    
  93.         $ticketAssignAgent $agent->getId();
  94.         $currentUser $user->getId();
  95.     }
  96.         
  97.         // Mark as viewed by agents
  98.         if (false == $ticket->getIsAgentViewed()) {
  99.             $ticket->setIsAgentViewed(true);
  100.             $entityManager->persist($ticket);
  101.             $entityManager->flush();
  102.         }
  103.     
  104.         // Ticket Authorization
  105.         $supportRole $user->getCurrentInstance()->getSupportRole()->getCode(); 
  106.         switch($supportRole) {
  107.             case 'ROLE_ADMIN':
  108.             case 'ROLE_SUPER_ADMIN':
  109.                 break;
  110.             case 'ROLE_AGENT':
  111.                 $accessLevel = (int) $user->getCurrentInstance()->getTicketAccessLevel();
  112.                 switch($accessLevel) {
  113.                     case TicketRepository::TICKET_GLOBAL_ACCESS:
  114.                         break;
  115.                     case TicketRepository::TICKET_GROUP_ACCESS:
  116.                         $supportGroups array_map(function($supportGroup) { return $supportGroup->getId(); }, $user->getCurrentInstance()->getSupportGroups()->getValues());                       
  117.                         $ticketAccessableGroups $ticket->getSupportGroup() ? [$ticket->getSupportGroup()->getId()] : [];
  118.  
  119.                         if ($ticket->getSupportTeam()) {
  120.                             $ticketSupportTeamGroups array_map(function($supportGroup) { return $supportGroup->getId(); }, $ticket->getSupportTeam()->getSupportGroups()->getValues());
  121.                             $ticketAccessableGroups array_merge($ticketAccessableGroups$ticketSupportTeamGroups);
  122.                         }
  123.                         $isAccessableGroupFound false;
  124.                         foreach($ticketAccessableGroups as $groupId) {
  125.                             if (in_array($groupId$supportGroups)) {
  126.                                 $isAccessableGroupFound true;
  127.                                 break;
  128.                             }
  129.                         }
  130.                         if (!$isAccessableGroupFound && !($ticketAssignAgent == $currentUser)) {
  131.                             throw new NotFoundHttpException('Page not found!');
  132.                         }
  133.                         break;
  134.                     case TicketRepository::TICKET_TEAM_ACCESS:
  135.                         $supportTeams array_map(function($supportTeam) { return $supportTeam->getId(); }, $user->getCurrentInstance()->getSupportTeams()->getValues());                         
  136.                         $supportTeam $ticket->getSupportTeam();
  137.                         if (!($supportTeam && in_array($supportTeam->getId(), $supportTeams)) && !($ticketAssignAgent == $currentUser)) {
  138.                             throw new NotFoundHttpException('Page not found!');
  139.                         }
  140.                         break;
  141.                     default:
  142.                         $collaborators array_map( function ($collaborator) { return $collaborator->getId(); }, $ticket->getCollaborators()->getValues());
  143.                         $accessableAgents array_merge($collaborators$ticket->getAgent() ? [$ticket->getAgent()->getId()] : []);
  144.                         if (!in_array($user->getId(), $accessableAgents)) {
  145.                             throw new NotFoundHttpException('Page not found!');
  146.                         }
  147.                         break;
  148.                 }
  149.                 break;
  150.             default:
  151.                 throw new NotFoundHttpException('Page not found!');
  152.         }
  153.         $quickActionButtonCollection->prepareAssets();
  154.         return $this->render('@UVDeskCoreFramework//ticket.html.twig', [
  155.             'ticket' => $ticket,
  156.             'totalReplies' => $ticketRepository->countTicketTotalThreads($ticket->getId()),
  157.             'totalCustomerTickets' => ($ticketRepository->countCustomerTotalTickets($customer$container) - 1),
  158.             'initialThread' => $this->ticketService->getTicketInitialThreadDetails($ticket),
  159.             'ticketAgent' => !empty($agent) ? $agent->getAgentInstance()->getPartialDetails() : null,
  160.             'customer' => $customer->getCustomerInstance()->getPartialDetails(),
  161.             'currentUserDetails' => $user->getAgentInstance()->getPartialDetails(),
  162.             'supportGroupCollection' => $userRepository->getSupportGroups(),
  163.             'supportTeamCollection' => $userRepository->getSupportTeams(),
  164.             'ticketStatusCollection' => $entityManager->getRepository(TicketStatus::class)->findAll(),
  165.             'ticketTypeCollection' => $entityManager->getRepository(TicketType::class)->findByIsActive(true),
  166.             'ticketPriorityCollection' => $entityManager->getRepository(TicketPriority::class)->findAll(),
  167.             'ticketNavigationIteration' => $ticketRepository->getTicketNavigationIteration($ticket$container),
  168.             'ticketLabelCollection' => $ticketRepository->getTicketLabelCollection($ticket$user),
  169.         ]);
  170.     }
  171.     public function saveTicket(Request $request)
  172.     {
  173.         $requestParams $request->request->all();
  174.         $entityManager $this->getDoctrine()->getManager();
  175.         $response $this->redirect($this->generateUrl('helpdesk_member_ticket_collection'));
  176.         if ($request->getMethod() != 'POST' || false == $this->userService->isAccessAuthorized('ROLE_AGENT_CREATE_TICKET')) {
  177.             return $response;
  178.         }
  179.         // Get referral ticket if any
  180.         $ticketValidationGroup 'CreateTicket';
  181.         $referralURL $request->headers->get('referer');
  182.         if (!empty($referralURL)) {
  183.             $iterations explode('/'$referralURL);
  184.             $referralId array_pop($iterations);
  185.             $expectedReferralURL $this->generateUrl('helpdesk_member_ticket', ['ticketId' => $referralId], UrlGeneratorInterface::ABSOLUTE_URL);
  186.             if ($referralURL === $expectedReferralURL) {
  187.                 $referralTicket $entityManager->getRepository(CoreBundleTicket::class)->findOneById($referralId);
  188.                 if (!empty($referralTicket)) {
  189.                     $ticketValidationGroup 'CustomerCreateTicket';
  190.                 }
  191.             }
  192.         }
  193.         $ticketType $entityManager->getRepository(TicketType::class)->findOneById($requestParams['type']);
  194.         try {
  195.             if ($this->userService->isfileExists('apps/uvdesk/custom-fields')) {
  196.                 $customFieldsService $this->get('uvdesk_package_custom_fields.service');
  197.             } else if ($this->userService->isfileExists('apps/uvdesk/form-component')) {
  198.                 $customFieldsService $this->get('uvdesk_package_form_component.service');
  199.             }
  200.             if (!empty($customFieldsService)) {
  201.                 extract($customFieldsService->customFieldsValidation($request'user'));
  202.             }
  203.         } catch (\Exception $e) {
  204.             // @TODO: Log execption message
  205.         }
  206.         if(!empty($errorFlashMessage)) {
  207.             $this->addFlash('warning'$errorFlashMessage);
  208.         }
  209.         
  210.         $ticketProxy = new CoreFrameworkBundleDataProxies\CreateTicketDataClass();
  211.         $form $this->createForm(CoreFrameworkBundleForms\CreateTicket::class, $ticketProxy);
  212.         // Validate Ticket Details
  213.         $form->submit($requestParams);
  214.         if (false == $form->isSubmitted() || false == $form->isValid()) {
  215.             if (false === $form->isValid()) {
  216.                 // @TODO: We need to handle form errors gracefully.
  217.                 // We should also look into switching to an xhr request instead.
  218.                 // $form->getErrors(true);
  219.             }
  220.             return $this->redirect(!empty($referralURL) ? $referralURL $this->generateUrl('helpdesk_member_ticket_collection'));
  221.         }
  222.         if ('CustomerCreateTicket' === $ticketValidationGroup && !empty($referralTicket)) {
  223.             // Retrieve customer details from referral ticket
  224.             $customer $referralTicket->getCustomer();
  225.             $customerPartialDetails $customer->getCustomerInstance()->getPartialDetails();
  226.         } else if (null != $ticketProxy->getFrom() && null != $ticketProxy->getName()) {
  227.             // Create customer if account does not exists
  228.             $customer $entityManager->getRepository(User::class)->findOneByEmail($ticketProxy->getFrom());
  229.             if (empty($customer) || null == $customer->getCustomerInstance()) {
  230.                 $role $entityManager->getRepository(SupportRole::class)->findOneByCode('ROLE_CUSTOMER');
  231.                 // Create User Instance
  232.                 $customer $this->userService->createUserInstance($ticketProxy->getFrom(), $ticketProxy->getName(), $role, [
  233.                     'source' => 'website',
  234.                     'active' => true
  235.                 ]);
  236.             }
  237.         }
  238.         $ticketData = [
  239.             'from' => $customer->getEmail(),
  240.             'name' => $customer->getFirstName() . ' ' $customer->getLastName(),
  241.             'type' => $ticketProxy->getType(),
  242.             'subject' => $ticketProxy->getSubject(),
  243.             // @TODO: We need to enable support for html messages. 
  244.             // Our focus here instead should be to prevent XSS (filter js)
  245.             'message' => str_replace(['&lt;script&gt;''&lt;/script&gt;'], ''htmlspecialchars($ticketProxy->getReply())),
  246.             'firstName' => $customer->getFirstName(),
  247.             'lastName' => $customer->getLastName(),
  248.             'type' => $ticketProxy->getType(),
  249.             'role' => 4,
  250.             'source' => 'website',
  251.             'threadType' => 'create',
  252.             'createdBy' => 'agent',
  253.             'customer' => $customer,
  254.             'user' => $this->getUser(),
  255.             'attachments' => $request->files->get('attachments'),
  256.         ];
  257.         $thread $this->ticketService->createTicketBase($ticketData);
  258.         // Trigger ticket created event
  259.         try {
  260.             $event = new GenericEvent(CoreWorkflowEvents\Ticket\Create::getId(), [
  261.                 'entity' =>  $thread->getTicket(),
  262.             ]);
  263.             $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  264.         } catch (\Exception $e) {
  265.             // Skip Automation
  266.         }
  267.         if (!empty($thread)) {
  268.             $ticket $thread->getTicket();
  269.             if ($request->request->get('customFields') || $request->files->get('customFields')) {
  270.                 $this->ticketService->addTicketCustomFields($thread$request->request->get('customFields'), $request->files->get('customFields'));                        
  271.             }
  272.             $this->addFlash('success'$this->translator->trans('Success ! Ticket has been created successfully.'));
  273.             if ($this->userService->isAccessAuthorized('ROLE_ADMIN')) {
  274.                 return $this->redirect($this->generateUrl('helpdesk_member_ticket', ['ticketId' => $ticket->getId()]));
  275.             }
  276.         } else {
  277.             $this->addFlash('warning'$this->translator->trans('Could not create ticket, invalid details.'));
  278.         }
  279.         return $this->redirect(!empty($referralURL) ? $referralURL $this->generateUrl('helpdesk_member_ticket_collection'));
  280.     }
  281.     public function listTicketTypeCollection(Request $request)
  282.     {
  283.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  284.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  285.         }
  286.         return $this->render('@UVDeskCoreFramework/ticketTypeList.html.twig');
  287.     }
  288.     public function ticketType(Request $request)
  289.     {
  290.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TICKET_TYPE')) {
  291.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  292.         }
  293.         $errorContext = [];
  294.         $em $this->getDoctrine()->getManager();
  295.         if ($id $request->attributes->get('ticketTypeId')) {
  296.             $type $em->getRepository(TicketType::class)->find($id);
  297.             
  298.             if (!$type) {
  299.                 $this->noResultFound();
  300.             }
  301.         } else {
  302.             $type = new CoreFrameworkBundleEntities\TicketType();
  303.         }
  304.         if ($request->getMethod() == "POST") {
  305.             $data $request->request->all();
  306.             $ticketType $em->getRepository(TicketType::class)->findOneByCode($data['code']);
  307.             if (!empty($ticketType) && $id != $ticketType->getId()) {
  308.                 $this->addFlash('warning'sprintf('Error! Ticket type with same name already exist'));
  309.             } else {
  310.                 $type->setCode($data['code']);
  311.                 $type->setDescription($data['description']);
  312.                 $type->setIsActive(isset($data['isActive']) ? 0);
  313.                 $em->persist($type);
  314.                 $em->flush();
  315.                 if (!$request->attributes->get('ticketTypeId')) {
  316.                     $this->addFlash('success'$this->translator->trans('Success! Ticket type saved successfully.'));
  317.                 } else {
  318.                     $this->addFlash('success'$this->translator->trans('Success! Ticket type updated successfully.'));
  319.                 }
  320.                 return $this->redirect($this->generateUrl('helpdesk_member_ticket_type_collection'));
  321.             }
  322.         }
  323.         return $this->render('@UVDeskCoreFramework/ticketTypeAdd.html.twig', array(
  324.             'type' => $type,
  325.             'errors' => json_encode($errorContext)
  326.         ));
  327.     }
  328.     public function listTagCollection(Request $request)
  329.     {
  330.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  331.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  332.         }
  333.         $enabled_bundles $this->getParameter('kernel.bundles');
  334.         return $this->render('@UVDeskCoreFramework/supportTagList.html.twig', [
  335.             'articlesEnabled' => in_array('UVDeskSupportCenterBundle'array_keys($enabled_bundles)),
  336.         ]);
  337.     }
  338.     public function removeTicketTagXHR($tagIdRequest $request)
  339.     {
  340.         if (!$this->userService->isAccessAuthorized('ROLE_AGENT_MANAGE_TAG')) {
  341.             return $this->redirect($this->generateUrl('helpdesk_member_dashboard'));
  342.         }
  343.         $json = [];
  344.         if($request->getMethod() == "DELETE") {
  345.             $em $this->getDoctrine()->getManager();
  346.             $tag $em->getRepository(Tag::class)->find($tagId);
  347.             if($tag) {
  348.                 $em->remove($tag);
  349.                 $em->flush();
  350.                 $json['alertClass'] = 'success';
  351.                 $json['alertMessage'] = $this->translator->trans('Success ! Tag removed successfully.');
  352.             }
  353.         }
  354.         $response = new Response(json_encode($json));
  355.         $response->headers->set('Content-Type''application/json');
  356.         return $response;
  357.     }
  358.     public function trashTicket(Request $request)
  359.     {
  360.         $ticketId $request->attributes->get('ticketId');
  361.         $entityManager $this->getDoctrine()->getManager();
  362.         $ticket $entityManager->getRepository(CoreBundleTicket::class)->find($ticketId);
  363.         if (!$ticket) {
  364.             $this->noResultFound();
  365.         }
  366.         $user $this->userService->getSessionUser();
  367.         // Proceed only if user has access to the resource
  368.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  369.             throw new \Exception('Access Denied'403);
  370.         }
  371.         if (!$ticket->getIsTrashed()) {
  372.             $ticket->setIsTrashed(1);
  373.             $entityManager->persist($ticket);
  374.             $entityManager->flush();
  375.         }
  376.         // Trigger ticket delete event
  377.         $event = new GenericEvent(CoreWorkflowEvents\Ticket\Delete::getId(), [
  378.             'entity' => $ticket,
  379.         ]);
  380.         $this->eventDispatcher->dispatch($event'uvdesk.automation.workflow.execute');
  381.         $this->addFlash('success'$this->translator->trans('Success ! Ticket moved to trash successfully.'));
  382.         return $this->redirectToRoute('helpdesk_member_ticket_collection');
  383.     }
  384.     // Delete a ticket ticket permanently
  385.     public function deleteTicket(Request $request)
  386.     {
  387.         $ticketId $request->attributes->get('ticketId');
  388.         $entityManager $this->getDoctrine()->getManager();
  389.         $ticket $entityManager->getRepository(CoreBundleTicket::class)->find($ticketId);
  390.         if (!$ticket) {
  391.             $this->noResultFound();
  392.         }
  393.         $user $this->userService->getSessionUser();
  394.         // Proceed only if user has access to the resource
  395.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  396.             throw new \Exception('Access Denied'403);
  397.         }
  398.         $entityManager->remove($ticket);
  399.         $entityManager->flush();
  400.         $this->addFlash('success'$this->translator->trans('Success ! Success ! Ticket Id #'$ticketId .' has been deleted successfully.'));
  401.         return $this->redirectToRoute('helpdesk_member_ticket_collection');
  402.     }
  403.     public function downloadZipAttachment(Request $request)
  404.     {
  405.         $threadId $request->attributes->get('threadId');
  406.         $attachmentRepository $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  407.         $threadRepository $this->getDoctrine()->getManager()->getRepository(Thread::class);
  408.         $thread $threadRepository->findOneById($threadId);
  409.         $attachment $attachmentRepository->findByThread($threadId);
  410.         if (!$attachment) {
  411.             $this->noResultFound();
  412.         }
  413.         $ticket $thread->getTicket();
  414.         $user $this->userService->getSessionUser();
  415.         
  416.         // Proceed only if user has access to the resource
  417.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  418.             throw new \Exception('Access Denied'403);
  419.         }
  420.         $zipname 'attachments/' .$threadId.'.zip';
  421.         $zip = new \ZipArchive;
  422.         $zip->open($zipname, \ZipArchive::CREATE);
  423.         if (count($attachment)) {
  424.             foreach ($attachment as $attach) {
  425.                 $zip->addFile(substr($attach->getPath(), 1));
  426.             }
  427.         }
  428.         $zip->close();
  429.         $response = new Response();
  430.         $response->setStatusCode(200);
  431.         $response->headers->set('Content-type''application/zip');
  432.         $response->headers->set('Content-Disposition''attachment; filename=' $threadId '.zip');
  433.         $response->sendHeaders();
  434.         $response->setContent(readfile($zipname));
  435.         return $response;
  436.     }
  437.     public function downloadAttachment(Request $request)
  438.     {   
  439.         $attachmentId $request->attributes->get('attachmendId');
  440.         $attachmentRepository $this->getDoctrine()->getManager()->getRepository(Attachment::class);
  441.         $attachment $attachmentRepository->findOneById($attachmentId);
  442.         $baseurl $request->getScheme() . '://' $request->getHttpHost() . $request->getBasePath();
  443.         if (!$attachment) {
  444.             $this->noResultFound();
  445.         }
  446.         $ticket $attachment->getThread()->getTicket();
  447.         $user $this->userService->getSessionUser();
  448.         
  449.         // Proceed only if user has access to the resource
  450.         if (false == $this->ticketService->isTicketAccessGranted($ticket$user)) {
  451.             throw new \Exception('Access Denied'403);
  452.         }
  453.         $path $this->kernel->getProjectDir() . "/public/"$attachment->getPath();
  454.         $response = new Response();
  455.         $response->setStatusCode(200);
  456.         $response->headers->set('Content-type'$attachment->getContentType());
  457.         $response->headers->set('Content-Disposition''attachment; filename='$attachment->getName());
  458.         $response->headers->set('Content-Length'$attachment->getSize());
  459.         $response->sendHeaders();
  460.         $response->setContent(readfile($path));
  461.         return $response;
  462.     }
  463.     /**
  464.      * If customer is playing with url and no result is found then what will happen
  465.      * @return 
  466.      */
  467.     protected function noResultFound()
  468.     {
  469.         throw new NotFoundHttpException('Not Found!');
  470.     }
  471. }