src/Controller/SaloonPreviewController.php line 52

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by simpson <simpsonwork@gmail.com>
  4.  * Date: 2019-04-15
  5.  * Time: 19:51
  6.  */
  7. namespace App\Controller;
  8. use App\Entity\Account\Customer;
  9. use App\Entity\Location\City;
  10. use App\Entity\Profile\Profile;
  11. use App\Entity\Saloon\Comment\CommentByCustomer;
  12. use App\Entity\Saloon\Saloon;
  13. use App\Entity\User;
  14. use App\Form\CommentForm;
  15. use App\Repository\ProfileRepository;
  16. use App\Repository\ServiceRepository;
  17. use App\Service\Features;
  18. use App\Specification\ElasticSearch\ProfileIsProvidingOneOfServices;
  19. use Carbon\CarbonImmutable;
  20. use Flagception\Bundle\FlagceptionBundle\Annotations\Feature;
  21. use Nelmio\ApiDocBundle\Attribute\Model;
  22. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  23. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  24. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
  25. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  26. use Symfony\Component\HttpFoundation\Request;
  27. use Symfony\Component\HttpFoundation\Response;
  28. use Symfony\Component\HttpKernel\Exception\GoneHttpException;
  29. use Symfony\Component\Routing\Annotation\Route;
  30. use OpenApi\Attributes as OA;
  31. class SaloonPreviewController extends AbstractController
  32. {
  33.     use ResponseTrait;
  34.     private const PROFILES_PER_PAGE 6;
  35.     /**
  36.      * @Feature("has_saloons")
  37.      */
  38.     #[ParamConverter('city'converter'city_converter')]
  39.     #[Entity('saloon'expr'repository.ofUriIdentityWithinCity(saloon, city)')]
  40.     #[Route("/api/saloons/city/{city}/preview/{saloon}"name"api.saloons.preview"methods"GET"format"json")]
  41.     #[OA\Tag(name"Preview")]
  42.     #[OA\Response(
  43.         response200,
  44.         description'Полная информация салона',
  45.         content: new OA\JsonContent(ref: new Model(typeSaloon::class, groups: ['preview''comments']))
  46.     )]
  47.     public function page(Request $requestCity $citySaloon $saloonServiceRepository $serviceRepositoryProfileRepository $profileRepositoryFeatures $featuresParameterBagInterface $parameterBag): Response
  48.     {
  49.         //  DMCA hard delete — всегда 404
  50.         if ($saloon->isHardDeleted()) {
  51.             throw $this->createNotFoundException();
  52.         }
  53.         $showHttp200FromDate $this->createDateFromParameter(
  54.             $parameterBag->get('app.profile.page.deleted_saloon_http_200_starting_from')
  55.         );
  56.         if ($saloon->isDeleted() && $saloon->getDeletedAt() < $showHttp200FromDate) {
  57.             throw new GoneHttpException();
  58.         }
  59.         if ($this->isApiRequest($request)) {
  60.             return $this->json($salooncontext: ['groups' => ['preview''comments']]);
  61.         }
  62.         //$entityManager->getFilters()->enable('not_deleted_saloon_filter');
  63.         $services $serviceRepository->allIndexedByGroup();
  64.         $providedServices array_map(
  65.             static fn($providedService) => $providedService->getService(),
  66.             $saloon->getProvidedServices()->toArray(),
  67.         );
  68.         $profilesTotalCount $profileRepository->countPublicProfilesBySaloon($saloon);
  69.         $profilesRotationSeed = (int)(new \DateTimeImmutable())->format('z');
  70.         $parameters = [
  71.             'saloon' => $saloon,
  72.             'services' => $services,
  73.             'rating' => $this->countAverageRating($saloon),
  74.             'recommendationSpec' => !empty($providedServices) ? new ProfileIsProvidingOneOfServices($providedServices) : null,
  75.             'saloon_profiles' => $profileRepository->findPublicProfilesBySaloonRotatedByPlacementStatus(
  76.                 $saloon,
  77.                 min(self::PROFILES_PER_PAGE$profilesTotalCount),
  78.                 0,
  79.                 $profilesRotationSeed
  80.             ),
  81.             'saloon_profiles_total_count' => $profilesTotalCount,
  82.             'saloon_profiles_per_page' => self::PROFILES_PER_PAGE,
  83.             'saloon_profiles_rotation_offset' => $profilesRotationSeed,
  84.         ];
  85.         return $this->render('SaloonPreview/page.html.twig'$parameters);
  86.     }
  87.     private function createDateFromParameter(string $value): CarbonImmutable
  88.     {
  89.         $value trim(html_entity_decode($valueENT_QUOTES), '"\' ');
  90.         $value preg_replace('/([+-]\d{2}:\d{2})([+-]\d{2}:\d{2})$/''$1'$value);
  91.         return CarbonImmutable::createFromTimeString($value);
  92.     }
  93.     #[ParamConverter('city'converter'city_converter')]
  94.     #[Entity('saloon'expr'repository.ofUriIdentityWithinCity(saloon, city)')]
  95.     public function profiles(City $citySaloon $saloonProfileRepository $profileRepositoryRequest $requestint $page): Response
  96.     {
  97.         if ($saloon->isHardDeleted()) {
  98.             throw $this->createNotFoundException();
  99.         }
  100.         $page max(1$page);
  101.         $profilesTotalCount $profileRepository->countPublicProfilesBySaloon($saloon);
  102.         $profilesRotationSeed = (int)$request->query->get('rotation'0);
  103.         $loadedProfilesCount = ($page 1) * self::PROFILES_PER_PAGE;
  104.         $limit min(self::PROFILES_PER_PAGEmax(0$profilesTotalCount $loadedProfilesCount));
  105.         $profiles $profileRepository->findPublicProfilesBySaloonRotatedByPlacementStatus(
  106.             $saloon,
  107.             $limit,
  108.             $loadedProfilesCount,
  109.             $profilesRotationSeed
  110.         );
  111.         return $this->render('SaloonPreview/_profiles_list.html.twig', [
  112.             'profiles' => $profiles,
  113.         ]);
  114.     }
  115.     protected function countAverageRating(Saloon $saloon): float
  116.     {
  117.         $scores 0;
  118.         $totalScore 0;
  119.         $saloon->getComments()->map(function (CommentByCustomer $comment) use (&$scores, &$totalScore): void {
  120.             $scores++;
  121.             $totalScore += $comment->getMark();
  122.         });
  123.         $rating $scores $totalScore $scores 0;
  124.         $whole floor($rating);
  125.         $fraction $rating $whole;
  126.         $decimalRating 0;
  127.         if ($fraction 0.25)
  128.             $decimalRating 0;
  129.         elseif ($fraction >= 0.25 && $fraction 0.75)
  130.             $decimalRating 0.5;
  131.         elseif ($fraction >= 0.75)
  132.             $decimalRating 1;
  133.         $rating $whole $decimalRating;
  134.         return $rating;
  135.     }
  136. }