src/Controller/BaseAbstractController.php line 366

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Company;
  4. use App\Entity\Form\AnySearch;
  5. use App\Entity\User;
  6. use App\Entity\UserSettings;
  7. use App\Enum\User\Permission;
  8. use App\Enum\Theme\Theme;
  9. use App\Enum\User\Role;
  10. use App\Library\ModalMessageManager;
  11. use App\Library\Route\RouteParamObjects;
  12. use App\Library\Utils\Other\Other;
  13. use App\Security\User\SecurityUser;
  14. use App\Service\AccessToken\AccessTokenService;
  15. use App\Service\CarWash\CarWashService;
  16. use App\Service\ClientLegal\ClientLegalService;
  17. use App\Service\Company\CompanyService;
  18. use App\Service\Image\ImageService;
  19. use App\Service\Notification\NotificationService;
  20. use App\Service\RouteService;
  21. use App\Service\ServiceRetriever;
  22. use App\Service\ThemeService;
  23. use App\Service\FileService;
  24. use App\Service\User\UserService;
  25. use Doctrine\Common\Collections\ArrayCollection;
  26. use Doctrine\ORM\EntityManagerInterface;
  27. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  28. use Symfony\Component\Form\FormInterface;
  29. use Symfony\Component\Form\FormTypeInterface;
  30. use Symfony\Component\HttpFoundation\File\UploadedFile;
  31. use Symfony\Component\HttpFoundation\JsonResponse;
  32. use Symfony\Component\HttpFoundation\Request;
  33. use Symfony\Component\HttpFoundation\RequestStack;
  34. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  35. use Symfony\Component\Routing\RouterInterface;
  36. use Symfony\Component\Security\Core\Security;
  37. use Symfony\Component\Validator\Validator\ValidatorInterface;
  38. use Symfony\Component\HttpFoundation\Response;
  39. use App\Security\Authenticator;
  40. use Symfony\Component\Security\Core\Exception\AccessDeniedException as HttpAccessDeniedException;
  41. abstract class BaseAbstractController extends AbstractController
  42. {
  43.     const LOCATION_IF_ROUTE_NOT_AVAILABLE "/admin/clients";
  44.     private $todayStart null;
  45.     private $todayEnd null;
  46.     /**
  47.      * @var RequestStack
  48.      */
  49.     private $requestStack;
  50.     /**
  51.      * @var RouteService
  52.      */
  53.     protected $routeService;
  54.     /**
  55.      * @var FileService
  56.      */
  57.     private $fileService;
  58.     /**
  59.      * @var RouterInterface
  60.      */
  61.     private $router;
  62.     /**
  63.      * @var CarWashService
  64.      */
  65.     private $carWashService;
  66.     /**
  67.      * @var SessionInterface
  68.      */
  69.     private $session;
  70.     /**
  71.      * @var EntityManagerInterface
  72.      */
  73.     protected $em;
  74.     /**
  75.      * @var ClientLegalService
  76.      */
  77.     private $clientLegalService;
  78.     /**
  79.      * @var NotificationService
  80.      */
  81.     protected $notificationService;
  82.     /**
  83.      * @var ModalMessageManager
  84.      */
  85.     protected $modalMessageManager;
  86.     /**
  87.      * @var ServiceRetriever
  88.      */
  89.     protected $serviceRetriever;
  90.     /**
  91.      * @var Security
  92.      */
  93.     protected $security;
  94.     /**
  95.      * @var ValidatorInterface
  96.      */
  97.     protected $validator;
  98.     /**
  99.      * @var ImageService
  100.      */
  101.     private $imageService;
  102.     private UserService $userService;
  103.     private AccessTokenService $accessTokenService;
  104.     private ?string $onAuthenticationFailUrl null;
  105.     /**
  106.      * FrontendApiController constructor.
  107.      * @param RequestStack $requestStack
  108.      *
  109.      * auto unpack data
  110.      */
  111.     public function __construct(Security                    $securityRequestStack $requestStack,
  112.                                 ValidatorInterface          $validatorRouteService $routeService,
  113.                                 RouterInterface             $routerSessionInterface $sessionEntityManagerInterface $em,
  114.                                 FileService $fileService,
  115.                                 ServiceRetriever $serviceRetrieverImageService $imageService null,
  116.                                 UserService $userServiceAccessTokenService $accessTokenService)
  117.     {
  118.         $this->security $security;
  119.         $this->validator $validator;
  120.         $this->routeService $routeService;
  121.         $this->router $router;
  122.         $this->requestStack $requestStack;
  123.         $this->fileService $fileService;
  124.         $this->session $session;
  125.         $this->em $em;
  126.         $this->userService $userService;
  127.         $this->accessTokenService $accessTokenService;
  128.         $this->serviceRetriever $serviceRetriever;
  129.         $this->checkAuthentication();
  130.         $this->checkRouteAccess();
  131.         $routeName $this->getRouteName();
  132. //         $routeWrapper = $routeName ? $this->routeService->getRouteWrapper($routeName) : null;
  133. //         if (!$userService->isRouteAvailable($routeName) || ($routeWrapper && (!$routeWrapper->isOn() || $routeWrapper->isInDevelopment()))) {
  134. // //            return $this->redirectToRoute($userService->getAvailableRoute()); //symfony bug - cant get container here
  135. //             if ($userService->isClientLegalUser()) {
  136. //                 header('Location: /admin/profile');
  137. //             } else {
  138. //                 header('Location: ' . self::LOCATION_IF_ROUTE_NOT_AVAILABLE);
  139. //             }
  140. //             exit;
  141. //         }
  142. //        $companyStatus = $user->getCompany() ? $user->getCompany()->getStatus() : '';
  143. //        if ($companyStatus == Status::STATUS_BLOCKED && strpos($_SERVER['REQUEST_URI'],'paymen')===false) {
  144. //            header('Location: /admin/payment');
  145. //            exit;
  146. //        }
  147.         // $this->modalMessageManager = $modalMessageManager;
  148.         $this->imageService $imageService;
  149.     }
  150.     private function checkAuthentication(): void
  151.     {
  152.         $request $this->getRequest();
  153.         $uri $request->getRequestUri();
  154.         $isMessengerRoute preg_match("/^\/1bc3f6fdaea8f6ae35($|.)/"$uri);
  155.         if (!$this->security->getUser()
  156.             && !in_array($this->getRouteName(), ["zoom_webhook"])) {
  157.             if ($this->getRouteName() !== Authenticator::LOGIN_ROUTE
  158.                 && $this->getRouteName() !== "messenger_login" && !$isMessengerRoute && $uri != "/") {
  159.                 $this->onAuthenticationFailure();
  160.             }
  161.         }
  162.     }
  163.     protected function onAuthenticationFailure()
  164.     {
  165.         header('Location: ' $this->getOnAuthenticationFailUrl());
  166.         exit();
  167.     }
  168.     public function setOnAuthenticationFailUrl(string $url)
  169.     {
  170.         $this->onAuthenticationFailUrl $url;
  171.     }
  172.     public function getOnAuthenticationFailUrl(): string
  173.     {
  174.         if (!$this->onAuthenticationFailUrl) {
  175.             return Authenticator::ON_AUTHENTICATION_FAIL_URL;
  176.         }
  177.         return $this->onAuthenticationFailUrl;
  178.     }
  179.     const ROUTES_DATA = [
  180.         'moderator_subscriber_edit' => [
  181.             'permission' => Permission::PERMISSION_CAN_EDIT_STUDENTS,
  182.         ],
  183.         'moderator_subscriber_delete' => [
  184.             'permission' => Permission::PERMISSION_CAN_EDIT_STUDENTS,
  185.         ],
  186.         'moderator_candidate_edit' => [
  187.             'permission' => Permission::PERMISSION_CAN_EDIT_CANDIDATES,
  188.         ],
  189.         'moderator_candidate_delete' => [
  190.             'permission' => Permission::PERMISSION_CAN_EDIT_CANDIDATES,
  191.         ],
  192.         'moderator__telegram_campaigns' => [
  193.             'permission' => Permission::PERMISSION_CAN_VIEW_CAMPAIGNS,
  194.         ],
  195.         'moderator__payment_requisites' => [
  196.             'permission' => Permission::PERMISSION_CAN_VIEW_PAYMENT_REQUISITES,
  197.         ],
  198.     ];
  199.     private function checkRouteAccess(): void
  200.     {
  201.         /** @var User $user */
  202.         $user $this->security->getUser();
  203.         if (!$user) {
  204.             return;
  205.         }
  206.         $routeName $this->getRouteName();
  207.         if (!$this->isRouteAccessibleByPermission($routeName$user)) {
  208.             throw new HttpAccessDeniedException();
  209.         }
  210.          // admins and developers have all rights regardless of user settings
  211.         if (in_array($routeName, ['moderator_calendar_events'])) {
  212.             if (!$user->getSettings()->isCanViewCalendarEvents()) {
  213.                 throw new HttpAccessDeniedException();
  214.             }
  215.         } elseif (in_array($routeName, ['moderator_calendar_event_edit'])) {
  216.             if (!$user->getSettings()->isCanEditCalendarEvents()) {
  217.                 throw new HttpAccessDeniedException();
  218.             }
  219.         } elseif (in_array($routeName, ['moderator_student_edit'])) {
  220.             if (!$user->getSettings()->isCanEditStudents()) {
  221.                 throw new HttpAccessDeniedException();
  222.             }
  223.         } elseif (in_array($routeName, ['moderator_students'])) {
  224.             if (!$user->getSettings()->isCanViewStudents()) {
  225.                 throw new HttpAccessDeniedException();
  226.             }
  227.         } elseif (in_array($routeName, ['moderator_payment_edit'])) {
  228.             if (!$user->getSettings()->isCanEditPayments()) {
  229.                 throw new HttpAccessDeniedException();
  230.             }
  231.         } elseif (in_array($routeName, ['moderator_payments'])) {
  232.             if (!$user->getSettings()->isCanViewPayments()) {
  233.                 throw new HttpAccessDeniedException();
  234.             }
  235.         } elseif (in_array($routeName, ['moderator_candidates'])) {
  236.             if (!$user->getSettings()->isCanViewCandidates()) {
  237.                 throw new HttpAccessDeniedException();
  238.             }
  239.         } elseif (in_array($routeName, ['moderator_candidates_review'])) {
  240.             if (!$user->getSettings()->isCanReviewCandidates()) {
  241.                 throw new HttpAccessDeniedException();
  242.             }
  243.         } elseif (in_array($routeName, ['moderator_lists_zoom'])) {
  244.             if (!$user->getSettings()->isCanViewZoomReport()) {
  245.                 throw new HttpAccessDeniedException();
  246.             }
  247.         } elseif (in_array($routeName, ['moderator_payments_by_persons_report'])) {
  248.             if (!$user->getSettings()->isCanViewPaymentsReport()) {
  249.                 throw new HttpAccessDeniedException();
  250.             }
  251.         } elseif (in_array($routeName, ['moderator_inner_payments'])) {
  252.             if (!$user->getSettings()->isCanViewInnerPayments()) {
  253.                 throw new HttpAccessDeniedException();
  254.             }
  255.         } elseif (in_array($routeName, ['moderator_candidate_toggle_inner_payment'])) {
  256.             if (!$user->getSettings()->isCanEditInnerPayments()) {
  257.                 throw new HttpAccessDeniedException();
  258.             }
  259.         }
  260.     }
  261.     private function isRouteAccessibleByPermission(string $routeNameUser $user): bool
  262.     {
  263.         if (!isset(self::ROUTES_DATA[$routeName])) {
  264.             return true;
  265.         }
  266.         $permission self::ROUTES_DATA[$routeName]['permission'] ?? null;
  267.         if ($permission) {
  268.             return $user->getSettings()->getPermission($permission) === true;
  269.         }
  270.         return true;
  271.     }
  272.     // public function isDemo(): bool
  273.     // {
  274.     //     return $this->security->getUser()->isDemoRole();
  275.     // }
  276.     // public function isDesigner(): bool
  277.     // {
  278.     //     return $this->security->getUser()->isDesignerRole();
  279.     // }
  280.     public function redirectOnPostInDemo(Request $request)
  281.     {
  282.         /** @var SecurityUser $user */
  283.         $user $this->security->getUser();
  284.         if (($user->isDemoRole() || $user->isDesignerRole()) && $request->getMethod() == "POST") {
  285.             $redirectUrl null;
  286.             try {
  287.                 /** @var \Symfony\Component\HttpFoundation\Request $request */
  288.                 $redirectUrl $request->headers->get('referer');
  289.             } catch (\Exception $exception) {};
  290.             $this->addFlash('errors'"Невозможно изменить данные в демо-режиме");
  291.             header('Location: ' . ($redirectUrl ?? self::LOCATION_IF_ROUTE_NOT_AVAILABLE));
  292.             exit;
  293.         }
  294.     }
  295.     public function validate($item): bool
  296.     {
  297.         $errors $this->validator->validate($item);
  298.         if ($errors->count()) {
  299.             foreach ($errors as $error) {
  300.                 $this->addFlash('errors'$error->getMessage());
  301.             }
  302.             return false;
  303.         }
  304.         return true;
  305.     }
  306.     public function handleValidationResult($validationResult): bool
  307.     {
  308.        if (is_bool($validationResult)) {
  309.            return $validationResult;
  310.        } else {
  311.            foreach ($validationResult as $error) {
  312.                $this->addFlash('errors'$error);
  313.            }
  314.            return false;
  315.        }
  316.    }
  317.     // public function getCompany(): ?Company
  318.     // {
  319.     //     return $this->companyService->get($this->security->getUser()->getCompany());
  320.     // }
  321.     // protected function isAdmin(): bool
  322.     // {
  323.         // $user = ($this->security->getUser() ? $this->security->getUser()->getAssociatedUser() : null);
  324.         // return $user instanceof User && $user->getRole() == Role::ROLE_ADMIN;
  325.     // }
  326.     // protected function getSecurityUser(): SecurityUser
  327.     // {
  328.     //     return $this->security->getUser();
  329.     // }
  330.     public function getLoggedInUser(): ?User
  331.     {
  332.         return $this->userService->getLoggedInUser();
  333.     }
  334.     public function isAdminMainRoute(): bool
  335.     {
  336.         return preg_match("/^admin_main/"$this->requestStack->getCurrentRequest()->get('_route'));
  337.     }
  338.     public function setFile($form, array $requestData$itemstring $fieldstring $filesSubPathbool $changeFileName true)
  339.     {
  340.         $this->fileService->setEntityFile($item$requestData$field$form$filesSubPath$changeFileName);
  341.     }
  342.     public function setImage($form$item, array $requestDatastring $fieldstring $imagesSubPath)
  343.     {
  344.         $this->setFile($form$requestData$item$field$imagesSubPath);
  345.     }
  346.     public function getRouteName(): ?string
  347.     {
  348.         return $this->requestStack->getCurrentRequest()->get('_route');
  349.     }
  350.     public function getRouteParamNames(string $route null): array
  351.     {
  352.         if (!$route) {
  353.             $route $this->getRouteName();
  354.         }
  355.         $routeCollection $this->router->getRouteCollection();
  356.         $route $routeCollection->get($route);
  357.         $parameterNames $route->compile()->getVariables();
  358.         return $parameterNames;
  359.     }
  360.     public function getRequest(): Request
  361.     {
  362.         return $this->requestStack->getCurrentRequest();
  363.     }
  364.     /**
  365.      * @param Request $request
  366.      * @param $handleCallback
  367.      * Example: function (array $post, &$status, &$message, &$content) { }
  368.      * @return Response
  369.      */
  370.     public function handleAjax(Request $request$handleCallback): Response
  371.     {
  372.         throw new \Exception('');
  373.         // $status = 200;
  374.         // $content = null;
  375.         // $message = null;
  376.         // $error = null;
  377.         // try {
  378.         //     $post = json_decode($request->getContent(), true);
  379.         //     $handleCallback($post, $status, $message, $content);
  380.         // } catch (\Throwable $exception) {
  381.         //     Other::appendLog('', \App\Controller\Admin\MainController::errorLogPath, [
  382.         //         'class' => __CLASS__,
  383.         //         'method' => __FUNCTION__,
  384.         //         'line' => __LINE__,
  385.         //         'error' => "AJAX error: ",
  386.         //         $exception
  387.         //     ]);
  388.         //     $status = $status == 200 ? 500 : $status;
  389.         //     $error = $exception->getMessage();
  390.         // } finally {
  391.         //     $response = json_encode([
  392.         //         "content" => $content,
  393.         //         "message" => $message,
  394.         //         "error" => $error,
  395.         //         "status" => $status,
  396.         //         "postedData" => $post,
  397.         //     ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
  398.         //     return new Response($response, $status);
  399.         // }
  400.     }
  401.     public function addErrorFlashes(array $errors)
  402.     {
  403.         foreach ($errors as $error) {
  404.             $this->addFlash("errors"$error);
  405.         }
  406.     }
  407.     public function addSuccessFlashes(array $errors)
  408.     {
  409.         foreach ($errors as $error) {
  410.             $this->addFlash("success"$error);
  411.         }
  412.     }
  413.     // public function createSearch(): AnySearch
  414.     // {
  415.     //     $request = $this->getRequest();
  416.     //     return new AnySearch($request->get('page'));
  417.     // }
  418.     public function persistAll(array $entities)
  419.     {
  420.         foreach ($entities as $entity) {
  421.             $this->em->persist($entity);
  422.         }
  423.     }
  424.     public function getTodayStart(): \DateTime
  425.     {
  426.         if ($this->todayStart) {
  427.             return $this->todayStart;
  428.         }
  429.         $this->todayStart = (new \DateTime())->setTime(00);
  430.         return $this->todayStart;
  431.     }
  432.     public function getTodayEnd(): \DateTime
  433.     {
  434.         if ($this->todayEnd) {
  435.             return $this->todayEnd;
  436.         }
  437.         $this->todayEnd = (new \DateTime())->setTime(235959);
  438.         return $this->todayEnd;
  439.     }
  440.     public function getFormType(FormInterface $form): FormTypeInterface
  441.     {
  442.         return $form->getConfig()->getType()->getInnerType();
  443.     }
  444.     public function getRouteParamObjects(): RouteParamObjects
  445.     {
  446.         return $this->routeService->getRouteObjects();
  447.     }
  448.     // protected function render(string $view, array $parameters = [], Response $response = null): Response
  449.     // {
  450.     //     //todo убрать этот метод в будущем после перехода на новый дизайн
  451.     //     if ($view == "admin/base.html.twig") {
  452.     //         return parent::render($view, $parameters, $response);
  453.     //     }
  454.     //     return parent::render($this->themeService->getTemplate($view, $this->getRouteName()), $parameters, $response);
  455.     // }
  456.     /**
  457.      * @param $callback
  458.      * @param null|callable $onSuccess
  459.      * @param array $handleExceptions
  460.      * @return void|null
  461.      * @throws \Throwable
  462.      */
  463.     protected function tryWithFlashError($callback, ?callable $onSuccess, array $handleExceptions)
  464.     {
  465.         Other::tryDo($callbacknull,
  466.             function (\Throwable $throwable) {
  467.                 $this->addFlash("errors"$throwable->getMessage());
  468.                 return null;
  469.             },
  470.             null$onSuccess$handleExceptions);
  471.     }
  472.     public function handleEntityCollectionField($entityFormInterface $formRequest $requeststring $fieldNameArrayCollection $originalItemsCollection,
  473.                                                 $afterCollectionItemPersistCallback null$beforeCollectionItemRemoveCallback null)
  474.     {
  475.         if ($form->has($fieldName)) {
  476.             $collectionForm $form->get($fieldName);
  477.             foreach ($collectionForm as $childForm) {
  478.                 $collectionItem $childForm->getData();
  479.                 if ($collectionItem && null === $collectionItem->getId()) {
  480.                     $this->em->persist($collectionItem);
  481.                 }
  482.                 if ($collectionItem && $afterCollectionItemPersistCallback) {
  483.                     $afterCollectionItemPersistCallback($collectionItem$childForm);
  484.                 }
  485.             }
  486.         }
  487.         // Определяем удалённые сообщения: те, что были в originalMessages, но их нет в текущей коллекции
  488.         $method "get" ucfirst($fieldName);
  489.         foreach ($originalItemsCollection as $origCollectionItem) {
  490.             if (!$entity->$method()->contains($origCollectionItem)) {
  491.                 // удалённый элемент
  492.                 $beforeCollectionItemRemoveCallback($origCollectionItem);
  493.                 // удалить сам объект сообщения
  494.                 $this->em->remove($origCollectionItem);
  495.             }
  496.         }
  497.     }
  498.     public function isUserAdmin(): bool
  499.     {
  500.         $user $this->getUser();
  501.         return $user && in_array(Role::ROLE_ADMIN$user->getRoles());
  502.     }
  503.     protected function getUserSettings(): ?UserSettings
  504.     {
  505.         $user $this->getLoggedInUser();
  506.         if (!$user) {
  507.             return null;
  508.         }
  509.         return $user->getSettings();
  510.     }
  511.     protected function handleRequestWithAccessToken($callback): Response
  512.     {
  513.         $token $this->accessTokenService->getByCookies();
  514.         if (!$token || (!$token->isAlive() && !$token->isRefreshable())) {
  515.             $this->onAuthenticationFailure();
  516.         }
  517.         $response $callback();
  518.         if (!$token->isAlive()) {
  519.             $token $this->accessTokenService->refresh($tokentrue);
  520.             $this->accessTokenService->setResponseCookie($response$token);
  521.         }
  522.         return $response;
  523.     }
  524.     public function uploadFile(Request $request): JsonResponse
  525.     {
  526.         /** @var UploadedFile|null $file */
  527.         $file $request->files->get('file');
  528.         if (!$file) {
  529.             return $this->json([
  530.                 'success' => false,
  531.                 'message' => 'File is required.'
  532.             ], 400);
  533.         }
  534.         unlink($file->getRealPath());
  535.         return new JsonResponse([]);
  536.     }
  537. }