src/Controller/DistributorUsersController.php line 339

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\ClinicUsers;
  4. use App\Entity\DistributorUserPermissions;
  5. use App\Entity\DistributorUsers;
  6. use App\Entity\UserPermissions;
  7. use App\Form\ResetPasswordRequestFormType;
  8. use App\Services\PaginationManager;
  9. use Doctrine\ORM\EntityManagerInterface;
  10. use Nzo\UrlEncryptorBundle\Encryptor\Encryptor;
  11. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  12. use Symfony\Component\HttpFoundation\JsonResponse;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\Response;
  15. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  16. use Symfony\Component\Routing\Annotation\Route;
  17. class DistributorUsersController extends AbstractController
  18. {
  19.     private $em;
  20.     private $pageManager;
  21.     private $plainPassword;
  22.     private $encryptor;
  23.     const ITEMS_PER_PAGE 2;
  24.     public function __construct(EntityManagerInterface $emPaginationManager $paginationEncryptor $encryptor)
  25.     {
  26.         $this->em $em;
  27.         $this->pageManager $pagination;
  28.         $this->encryptor $encryptor;
  29.     }
  30.     #[Route('/distributors/get-user'name'distributor_get_user')]
  31.     public function distributorGetUserAction(Request $request): Response
  32.     {
  33.         $user $this->em->getRepository(DistributorUsers::class)->find($request->request->get('id'));
  34.         $userPermissions = [];
  35.         foreach($user->getDistributorUserPermissions() as $permission)
  36.         {
  37.             $userPermissions[] = $permission->getPermission()->getId();
  38.         }
  39.         $response = [
  40.             'id' => $user->getId(),
  41.             'first_name' => $this->encryptor->decrypt($user->getFirstName()),
  42.             'last_name' => $this->encryptor->decrypt($user->getLastName()),
  43.             'email' => $this->encryptor->decrypt($user->getEmail()),
  44.             'telephone' => $this->encryptor->decrypt($user->getTelephone()),
  45.             'position' => $this->encryptor->decrypt($user->getPosition()),
  46.             'iso_code' => $this->encryptor->decrypt($user->getIsoCode()),
  47.             'intl_code' => $this->encryptor->decrypt($user->getIntlCode()),
  48.             'permissions' => $user->getDistributorUserPermissions(),
  49.             'user_permissions' => $userPermissions,
  50.         ];
  51.         return new JsonResponse($response);
  52.     }
  53.     #[Route('/distributors/manage-users'name'distributor_users')]
  54.     public function distributorUsersAction(Request $requestUserPasswordHasherInterface $passwordHasher): Response
  55.     {
  56.         $data $request->request->get('distributor_users_form');
  57.         $distributor $this->get('security.token_storage')->getToken()->getUser()->getDistributor();
  58.         $user $this->em->getRepository(DistributorUsers::class)->findBy(['email' => $data['email']]);
  59.         $userId = (int) $data['user_id'];
  60.         if(count($user) > && $userId == 0){
  61.             $response = [
  62.                 'response' => false
  63.             ];
  64.             return new JsonResponse($response);
  65.         }
  66.         if($userId == 0){
  67.             $distributorUser = new DistributorUsers();
  68.             $plainTextPwd $this->generatePassword();
  69.             $distributorUser->setIsPrimary(0);
  70.             if (!empty($plainTextPwd)) {
  71.                 $hashedPwd $passwordHasher->hashPassword($distributorUser$plainTextPwd);
  72.                 $distributorUser->setRoles(['ROLE_DISTRIBUTOR']);
  73.                 $distributorUser->setPassword($hashedPwd);
  74.                 // Send Email
  75.                 $body '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';
  76.                 $body .= '<tr><td colspan="2">Hi '$data['firstName'] .',</td></tr>';
  77.                 $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  78.                 $body .= '<tr><td colspan="2">Please use the credentials below login to the Fluid Backend.</td></tr>';
  79.                 $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  80.                 $body .= '<tr>';
  81.                 $body .= '    <td><b>URL: </b></td>';
  82.                 $body .= '    <td><a href="https://'$_SERVER['HTTP_HOST'] .'/distributors/login">https://'$_SERVER['HTTP_HOST'] .'/distributors/login</a></td>';
  83.                 $body .= '</tr>';
  84.                 $body .= '<tr>';
  85.                 $body .= '    <td><b>Username: </b></td>';
  86.                 $body .= '    <td>'$data['email'] .'</td>';
  87.                 $body .= '</tr>';
  88.                 $body .= '<tr>';
  89.                 $body .= '    <td><b>Password: </b></td>';
  90.                 $body .= '    <td>'$plainTextPwd .'</td>';
  91.                 $body .= '</tr>';
  92.                 $body .= '</table>';
  93.                 $body $this->forward('App\Controller\ResetPasswordController::emailFooter', [
  94.                     'html'  => $body,
  95.                 ])->getContent();
  96.                 $subject 'Fluid Login Credentials';
  97.                 $emailTo $data['email'];
  98.                 exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($body) .'" "'$emailTo .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  99.             }
  100.             $message '<b><i class="fas fa-check-circle"></i> User details successfully created.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  101.         } else {
  102.             $distributorUser $this->em->getRepository(DistributorUsers::class)->find($userId);
  103.             $distributorUser->setIsPrimary($distributorUser->getIsPrimary());
  104.             $message '<b><i class="fas fa-check-circle"></i> User successfully updated.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  105.         }
  106.         $distributorUser->setDistributor($distributor);
  107.         $distributorUser->setFirstName($this->encryptor->encrypt($data['firstName']));
  108.         $distributorUser->setLastName($this->encryptor->encrypt($data['lastName']));
  109.         $distributorUser->setEmail($this->encryptor->encrypt($data['email']));
  110.         $distributorUser->setHashedEmail(md5($data['email']));
  111.         $distributorUser->setTelephone($this->encryptor->encrypt($data['telephone']));
  112.         $distributorUser->setIsoCode($this->encryptor->encrypt($data['isoCode']));
  113.         $distributorUser->setIntlCode($this->encryptor->encrypt($data['intlCode']));
  114.         $distributorUser->setPosition($this->encryptor->encrypt($data['position']));
  115.         $this->em->persist($distributorUser);
  116.         $this->em->flush();
  117.         // Update user permissions
  118.         // Primary account can't update permissions
  119.         if(!$distributorUser->getIsPrimary()) {
  120.             // Remove previous entries
  121.             $permissions $this->em->getRepository(DistributorUserPermissions::class)->findBy(['user' => $distributorUser->getId()]);
  122.             if (count($permissions) > 0) {
  123.                 foreach ($permissions as $permission) {
  124.                     $permissionRepo $this->em->getRepository(DistributorUserPermissions::class)->find($permission->getId());
  125.                     $this->em->remove($permissionRepo);
  126.                 }
  127.                 $this->em->flush();
  128.             }
  129.             // Save new permissions
  130.             if (array_key_exists('permission'$data)) {
  131.                 foreach ($data['permission'] as $permission) {
  132.                     $distributorUserPermission = new DistributorUserPermissions();
  133.                     $user $this->em->getRepository(DistributorUsers::class)->find($distributorUser->getId());
  134.                     $userPermission $this->em->getRepository(UserPermissions::class)->find($permission);
  135.                     $distributorUserPermission->setDistributor($distributor);
  136.                     $distributorUserPermission->setUser($user);
  137.                     $distributorUserPermission->setPermission($userPermission);
  138.                     $this->em->persist($distributorUserPermission);
  139.                 }
  140.                 $this->em->flush();
  141.             }
  142.         }
  143.         $response = [
  144.             'response' => true,
  145.             'message' => $message
  146.         ];
  147.         return new JsonResponse($response);
  148.     }
  149.     #[Route('/distributors/users-refresh'name'distributor_refresh_users')]
  150.     public function distributorRefreshUsersAction(Request $request): Response
  151.     {
  152.         $distributorId $this->get('security.token_storage')->getToken()->getUser()->getDistributor()->getId();
  153.         $users $this->em->getRepository(DistributorUsers::class)->findDistributorUsers($distributorId);
  154.         $userResults $this->pageManager->paginate($users[0], $requestself::ITEMS_PER_PAGE);
  155.         $pageId $request->request->get('page-id');
  156.         $html '';
  157.         foreach($userResults as $user){
  158.             $html .= '
  159.             <div class="row">
  160.                 <div 
  161.                     class="col-5 col-md-2 d-xl-none t-cell fw-bold bg-light border-bottom border-left text-primary text-truncate border-list pt-3 pb-3"
  162.                 >
  163.                     First Name:
  164.                 </div>
  165.                 <div 
  166.                     class="col-7 col-md-10 col-xl-2 border-list pt-3 pb-3 t-cell text-truncate bg-light border-right border-bottom" 
  167.                     id="string_user_first_name_'$user->getId() .'"
  168.                 >
  169.                     '$this->encryptor->decrypt($user->getFirstName()) .'
  170.                 </div>
  171.                 <div 
  172.                     class="col-5 col-md-2 d-xl-none t-cell fw-bold bg-light border-bottom text-primary text-truncate border-list pt-3 pb-3"
  173.                 >
  174.                     Last Name:
  175.                 </div>
  176.                 <div 
  177.                     class="col-7 col-md-10 col-xl-2 pt-3 pb-3 bg-light border-list border-bottom t-cell text-truncate"
  178.                     >
  179.                     '$this->encryptor->decrypt($user->getLastName()) .'
  180.                 </div>
  181.                 <div 
  182.                     class="col-5 col-md-2 d-xl-none t-cell fw-bold bg-light border-bottom border-left text-primary text-truncate border-list pt-3 pb-3"
  183.                 >
  184.                     Username:
  185.                 </div>
  186.                 <div 
  187.                     class="col-7 col-md-10 col-xl-2 pt-3 pb-3 bg-light border-list border-bottom t-cell text-truncate"
  188.                 >
  189.                     '$this->encryptor->decrypt($user->getEmail()) .'
  190.                 </div>
  191.                 <div 
  192.                     class="col-5 col-md-2 d-xl-none t-cell fw-bold bg-light border-bottom border-left text-primary text-truncate border-list pt-3 pb-3"
  193.                 >
  194.                     Telephone:
  195.                 </div>
  196.                 <div 
  197.                     class="col-7 col-md-10 col-xl-2 pt-3 pb-3 bg-light border-list border-bottom t-cell text-truncate"
  198.                 >
  199.                     '$this->encryptor->decrypt($user->getTelephone()) .'
  200.                 </div>
  201.                 <div 
  202.                     class="col-5 col-md-2 d-xl-none t-cell fw-bold bg-light border-bottom border-left text-primary text-truncate border-list pt-3 pb-3"
  203.                 >
  204.                     Position:
  205.                 </div>
  206.                 <div 
  207.                     class="col-7 col-md-10 col-xl-2 pt-3 pb-3 bg-light border-list border-bottom t-cell text-truncate"
  208.                 >
  209.                     '$this->encryptor->decrypt($user->getPosition()) .'
  210.                 </div>
  211.                 <div class="col-md-2 t-cell bg-light border-list border-right">
  212.                     <a href="" class="float-end update-user" data-bs-toggle="modal" data-bs-target="#modal_user" data-user-id="'$user->getId() .'">
  213.                         <i class="fa-solid fa-pen-to-square edit-icon"></i>
  214.                     </a>';
  215.                     if($user->getIsPrimary() != 1) {
  216.                         $html .= '
  217.                         <a href="" class="delete-icon float-end delete-user" data-bs-toggle="modal"
  218.                             data-value="' $user->getId() . '" data-bs-target="#modal_user_delete" data-user-id="' $user->getId() . '">
  219.                             <i class="fa-solid fa-trash-can"></i>
  220.                         </a>';
  221.                     }
  222.                 $html .= '
  223.                 </div>
  224.             </div>';
  225.         }
  226.         $pagination $this->getPagination($pageId$userResults$distributorId);
  227.         $html .= $pagination;
  228.         return new JsonResponse($html);
  229.     }
  230.     #[Route('/distributors/get/users-list'name'get_distributor_users_list')]
  231.     public function getDistributorUsersList(Request $request): Response
  232.     {
  233.         $distributorId $this->getUser()->getDistributor()->getId();
  234.         $users $this->em->getRepository(DistributorUsers::class)->findDistributorUsers($distributorId);
  235.         $userResults $this->pageManager->paginate($users[0], $requestself::ITEMS_PER_PAGE);
  236.         $pageId $request->request->get('page-id') ?? 1;
  237.         $userPermissions $this->em->getRepository(UserPermissions::class)->findBy([
  238.             'isDistributor' => 1,
  239.         ]);
  240.         $pagination $this->forward('App\Controller\ProductsController::getPagination', [
  241.             'pageId'  => $pageId,
  242.             'results' => $userResults,
  243.             'url' => '/distributors/users/',
  244.             'dataAction' => 'data-action="click->distributors--users#onClickPagintion"',
  245.             'itemsPerPage' => self::ITEMS_PER_PAGE,
  246.         ])->getContent();
  247.         $html $this->render('frontend/distributors/users.html.twig', [
  248.             'userResults' => $userResults,
  249.             'userPermissions' => $userPermissions,
  250.             'pagination' => $pagination,
  251.         ])->getContent();
  252.         return new JsonResponse($html);
  253.     }
  254.     #[Route('/distributors/user/delete'name'distributor_user_delete')]
  255.     public function distributorDeleteUser(Request $request): Response
  256.     {
  257.         $userId = (int) $request->request->get('id');
  258.         $user $this->em->getRepository(DistributorUsers::class)->find($userId);
  259.         $distributorUserPermissions $this->em->getRepository(DistributorUserPermissions::class)->findBy([
  260.             'user' => $userId,
  261.         ]);
  262.         if(count($distributorUserPermissions) > 0){
  263.             foreach ($distributorUserPermissions as $distributorUserPermission){
  264.                 $this->em->remove($distributorUserPermission);
  265.             }
  266.         }
  267.         $this->em->remove($user);
  268.         $this->em->flush();
  269.         $response '<b><i class="fas fa-check-circle"></i> User successfully deleted.<div class="flash-close"><i class="fa-solid fa-xmark"></i></div>';
  270.         return new JsonResponse($response);
  271.     }
  272.     #[Route('/distributors/forgot-password'name'distributors_forgot_password_request')]
  273.     public function clinicForgotPasswordAction(Request $request): Response
  274.     {
  275.         $form $this->createForm(ResetPasswordRequestFormType::class);
  276.         $form->handleRequest($request);
  277.         if ($form->isSubmitted() && $form->isValid()) {
  278.             $distributorUser $this->em->getRepository(DistributorUsers::class)->findOneBy(
  279.                 [
  280.                     'hashedEmail' => md5($request->request->get('reset_password_request_form')['email'])
  281.                 ]
  282.             );
  283.             if($distributorUser != null){
  284.                 $resetToken uniqid();
  285.                 $distributorUser->setResetKey($resetToken);
  286.                 $this->em->persist($distributorUser);
  287.                 $this->em->flush();
  288.                 $html '
  289.                 <p>To reset your password, please visit the following link</p>
  290.                 <p>
  291.                     <a
  292.                         href="https://'$_SERVER['HTTP_HOST'] .'/distributors/reset/'$resetToken .'"
  293.                     >https://'$_SERVER['HTTP_HOST'] .'/distributors/reset/'$resetToken .'</a>
  294.                 </p>';
  295.                 $html $this->forward('App\Controller\ResetPasswordController::emailFooter', [
  296.                     'html'  => $html,
  297.                 ]);
  298.                 $emailTo $this->encryptor->decrypt($distributorUser->getEmail());
  299.                 $subject 'Fluid Password Reset';
  300.                 exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($html->getContent()) .'" "'$emailTo .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  301.                 return $this->render('reset_password/distributors_check_email.html.twig');
  302.             }
  303.         }
  304.         return $this->render('reset_password/request.html.twig', [
  305.             'requestForm' => $form->createView(),
  306.         ]);
  307.     }
  308.     #[Route('/distributors/reset/{token}'name'distributors_reset_password')]
  309.     public function reset(Request $requestUserPasswordHasherInterface $passwordHasherstring $token null): Response
  310.     {
  311.         $plainTextPwd $this->generatePassword();
  312.         $distributorUser $this->em->getRepository(DistributorUsers::class)->findOneBy([
  313.             'resetKey' => $request->get('token')
  314.         ]);
  315.         if (!empty($plainTextPwd)) {
  316.             $hashedPwd $passwordHasher->hashPassword($distributorUser$plainTextPwd);
  317.             $distributorUser->setPassword($hashedPwd);
  318.             $this->em->persist($distributorUser);
  319.             $this->em->flush();
  320.             // Send Email
  321.             $body  '<p style="margin-bottom: 0">Hi '$this->encryptor->decrypt($distributorUser->getFirstName()) .',</p>';
  322.             $body .= '<br>';
  323.             $body .= '<p style="margin-bottom: 0">Please use the credentials below login to the Fluid Backend.</p>';
  324.             $body .= '<br>';
  325.             $body .= '<table style="border: none; font-family: Arial, Helvetica, sans-serif">';
  326.             $body .= '<tr>';
  327.             $body .= '    <td><b>URL: </b></td>';
  328.             $body .= '    <td><a href="https://'$_SERVER['HTTP_HOST'] .'/distributors/login">https://'$_SERVER['HTTP_HOST'] .'/distributors/login</a></td>';
  329.             $body .= '</tr>';
  330.             $body .= '<tr>';
  331.             $body .= '    <td><b>Username: </b></td>';
  332.             $body .= '    <td>'$this->encryptor->decrypt($distributorUser->getEmail()) .'</td>';
  333.             $body .= '</tr>';
  334.             $body .= '<tr>';
  335.             $body .= '    <td><b>Password: </b></td>';
  336.             $body .= '    <td>'$plainTextPwd .'</td>';
  337.             $body .= '</tr>';
  338.             $body .= '</table>';
  339.             $html $this->forward('App\Controller\ResetPasswordController::emailFooter', [
  340.                 'html'  => $body,
  341.             ]);
  342.             $subject 'Fluid Login Credentials';
  343.             $emailTo $this->encryptor->decrypt($distributorUser->getEmail());
  344.             exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($html->getContent()) .'" "'$emailTo .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  345.         }
  346.         return $this->redirectToRoute('distributors_password_reset');
  347.     }
  348.     #[Route('/distributors/password/reset'name'distributors_password_reset')]
  349.     public function distributorPasswordReset(Request $request): Response
  350.     {
  351.         return $this->render('reset_password/distributors_password_reset.html.twig');
  352.     }
  353.     private function generatePassword()
  354.     {
  355.         $sets = [];
  356.         $sets[] = 'abcdefghjkmnpqrstuvwxyz';
  357.         $sets[] = 'ABCDEFGHJKMNPQRSTUVWXYZ';
  358.         $sets[] = '23456789';
  359.         $sets[] = '!@$%*?';
  360.         $all '';
  361.         $password '';
  362.         foreach ($sets as $set) {
  363.             $password .= $set[array_rand(str_split($set))];
  364.             $all .= $set;
  365.         }
  366.         $all str_split($all);
  367.         for ($i 0$i 16 count($sets); $i++) {
  368.             $password .= $all[array_rand($all)];
  369.         }
  370.         $this->plainPassword str_shuffle($password);
  371.         return $this->plainPassword;
  372.     }
  373.     private function sendLoginCredentials($clinic_user$plainTextPwd$data)
  374.     {
  375.         // Send Email
  376.         $body '<table style="padding: 8px; border-collapse: collapse; border: none; font-family: arial">';
  377.         $body .= '<tr><td colspan="2">Hi '$data['firstName'] .',</td></tr>';
  378.         $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  379.         $body .= '<tr><td colspan="2">Please use the credentials below login to the Fluid Backend.</td></tr>';
  380.         $body .= '<tr><td colspan="2">&nbsp;</td></tr>';
  381.         $body .= '<tr>';
  382.         $body .= '    <td><b>URL: </b></td>';
  383.         $body .= '    <td><a href="https://'$_SERVER['HTTP_HOST'] .'/clinics/login">https://'$_SERVER['HTTP_HOST'] .'/clinics/login</a></td>';
  384.         $body .= '</tr>';
  385.         $body .= '<tr>';
  386.         $body .= '    <td><b>Username: </b></td>';
  387.         $body .= '    <td>'$data['email'] .'</td>';
  388.         $body .= '</tr>';
  389.         $body .= '<tr>';
  390.         $body .= '    <td><b>Password: </b></td>';
  391.         $body .= '    <td>'$plainTextPwd .'</td>';
  392.         $body .= '</tr>';
  393.         $body .= '</table>';
  394.         $subject 'Fluid Login Credentials';
  395.         $emailTo $data['email'];
  396.         exec(__DIR__ '/../../bin/console app:send-email "'$subject .'" "'addslashes($body) .'" "'$emailTo .'" "'serialize([]) .'" "'serialize([]) .'" "'true .'" > /dev/null 2>&1 &');
  397.     }
  398.     public function getPagination($pageId$results$distributorId)
  399.     {
  400.         $currentPage = (int) $pageId;
  401.         $lastPage $this->pageManager->lastPage($results);
  402.         $pagination '
  403.         <!-- Pagination -->
  404.         <div class="row mt-3">
  405.             <div class="col-12">';
  406.         if($lastPage 1) {
  407.             $previousPageNo $currentPage 1;
  408.             $url '/distributors/users';
  409.             $previousPage $url $previousPageNo;
  410.             $pagination .= '
  411.             <nav class="custom-pagination">
  412.                 <ul class="pagination justify-content-center">
  413.             ';
  414.             $disabled 'disabled';
  415.             $dataDisabled 'true';
  416.             // Previous Link
  417.             if($currentPage 1){
  418.                 $disabled '';
  419.                 $dataDisabled 'false';
  420.             }
  421.             $pagination .= '
  422.             <li class="page-item '$disabled .'">
  423.                 <a 
  424.                     class="user-pagination" 
  425.                     aria-disabled="'$dataDisabled .'" 
  426.                     data-page-id="'$currentPage .'" 
  427.                     data-distributor-id="'$distributorId .'"
  428.                     href="'$previousPage .'"
  429.                     data-action="click->distributors--users#onClickPagintion"
  430.                 >
  431.                     <span aria-hidden="true">&laquo;</span> <span class="d-none d-sm-inline">Previous</span>
  432.                 </a>
  433.             </li>';
  434.             for($i 1$i <= $lastPage$i++) {
  435.                 $active '';
  436.                 if($i == (int) $currentPage){
  437.                     $active 'active';
  438.                 }
  439.                 $pagination .= '
  440.                 <li class="page-item '$active .'">
  441.                     <a 
  442.                         class="user-pagination" 
  443.                         data-page-id="'$i .'" 
  444.                         href="'$url .'"
  445.                         data-distributor-id="'$distributorId .'"
  446.                         data-action="click->distributors--users#onClickPagintion"
  447.                     >'$i .'</a>
  448.                 </li>';
  449.             }
  450.             $disabled 'disabled';
  451.             $dataDisabled 'true';
  452.             if($currentPage $lastPage) {
  453.                 $disabled '';
  454.                 $dataDisabled 'false';
  455.             }
  456.             $pagination .= '
  457.             <li class="page-item '$disabled .'">
  458.                 <a 
  459.                     class="user-pagination" 
  460.                     aria-disabled="'$dataDisabled .'" 
  461.                     data-page-id="'$currentPage .'" 
  462.                     href="'$url .'"
  463.                     data-distributor-id="'$distributorId .'"
  464.                     data-action="click->distributors--users#onClickPagintion"
  465.                 >
  466.                     <span class="d-none d-sm-inline">Next</span> <span aria-hidden="true">&raquo;</span>
  467.                 </a>
  468.             </li>';
  469.             $pagination .= '
  470.                     </ul>
  471.                 </nav>';
  472.             $pagination .= '
  473.                 </div>
  474.             </div>';
  475.         }
  476.         return $pagination;
  477.     }
  478. }