src/Controller/ProfileFilterController.php line 51

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Dto\ProfileFilterFormData;
  4. use App\Dto\ProfileFilterFormDataFilters;
  5. use App\Dto\ProfileListSpecification;
  6. use App\Entity\Location\City;
  7. use App\Form\ProfileFilterForm;
  8. use App\Service\ProfileList;
  9. use App\Service\ProfileListingDataCreator;
  10. use App\Service\ProfileListingRecommendationsFiller;
  11. use App\Service\ListingRotationApi;
  12. use App\Service\ProfileTopBoard;
  13. use App\Service\ProfileFilterService;
  14. use Porpaginas\Page;
  15. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  16. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  20. class ProfileFilterController extends AbstractController
  21. {
  22.     use ResponseTrait;
  23.     public function __construct(
  24.         private ProfileListingDataCreator $profileListingDataCreator,
  25.         private ProfileFilterService $profilesFilterService,
  26.         private ProfileList $profileList,
  27.         private ProfileListingRecommendationsFiller $profileListingRecommendationsFiller,
  28.         private ListingRotationApi $listingRotationApi,
  29.         private ProfileTopBoard $profileTopBoard,
  30.     ) {}
  31.     #[ParamConverter("city"converter"city_converter")]
  32.     public function form(City $cityRequest $request): Response
  33.     {
  34.         if(!$request->isXmlHttpRequest()) {
  35.             throw new BadRequestHttpException();
  36.         }
  37.         $listing $request->request->get('listing');
  38.         $listingParameters json_decode($request->request->get('listingParams'), true);
  39.         $formData = new ProfileFilterFormData($listing$listingParameters, new ProfileFilterFormDataFilters());
  40.         $listingData $this->profileListingDataCreator->getListingDataForFilter($listing$listingParameters$city);
  41.         /** @var ProfileListSpecification $specs */
  42.         $specs $listingData['specs'];
  43.         //холостой вызов, чтобы сформировался запрос и записался в свойство ProfileList
  44.         $this->profileList->listActiveWithinCityOrderedByStatusWithSpecAvoidingTopPlacement($city$specs->spec(), $specs->additionalSpecs(), $specs->genders());
  45.         $this->profilesFilterService->checkProfilesPresenceByFilters($city$listingData['listingTypeName']);
  46.         $profilePresenceByFilters $this->profilesFilterService->profilesPresenceByFilters();
  47.         $form $this->createForm(ProfileFilterForm::class, $formData, [
  48.             'action'          => $this->generateUrl('profile_filters.filter', ['city' => $city->getUriIdentity()]),
  49.             'csrf_protection' => false,
  50.             'form_data' => $formData,
  51.             'profiles_presence_by_filters' => $profilePresenceByFilters,
  52.         ]);
  53.         return $this->prepareForXhr($this->render('ProfileList/filter/form.html.twig', [
  54.             'profiles_presence_by_filters' => $profilePresenceByFilters,
  55.             'profile_filter_form' => $form->createView(),
  56.         ]));
  57.     }
  58.     #[ParamConverter("city"converter"city_converter")]
  59.     public function filter(City $cityRequest $requestProfileFilterService $profilesFilterService): Response
  60.     {
  61.         if(!$request->isXmlHttpRequest()) {
  62.             throw new BadRequestHttpException();
  63.         }
  64.         $form $this->createForm(ProfileFilterForm::class, new ProfileFilterFormData('', [], new ProfileFilterFormDataFilters()), [
  65.             'action' => $this->generateUrl('profile_filters.filter', ['city' => $city->getUriIdentity()]),
  66.             'csrf_protection' => false,
  67.         ]);
  68.         $form->handleRequest($request);
  69.         if (false === $form->isSubmitted() || false === $form->isValid()) {
  70.             throw new BadRequestHttpException('Form is not submitted');
  71.         }
  72.         /** @var ProfileFilterFormData $formData */
  73.         $formData $form->getData();
  74. //        $specs = $this->profileListSpecificationService->{$listingType}(...$listingArgs);
  75.         $listingData $this->profileListingDataCreator->getListingDataForFilter($formData->listing$formData->listingParameters$city);
  76.         $specs $listingData['specs'];
  77.         $listingTypeName $listingData['listingTypeName'];
  78.         if ($this->shouldUseOriginalListingSource($formData)) {
  79.             $this->profileList->listActiveWithinCityOrderedByStatusWithSpecAvoidingTopPlacement($city$specs->spec(), $specs->additionalSpecs(), $specs->genders());
  80.             $profilesFilterService->checkProfilesPresenceByFilters($city$listingTypeName);
  81.             $presence $profilesFilterService->profilesPresenceByFilters();
  82.             try {
  83.                 $topPlacement $this->profileTopBoard->topPlacementSatisfiedBy($city$specs->spec());
  84.                 $topPlacement?->setTopCard();
  85.                 $result $this->listingRotationApi->paginate(
  86.                     '/city/{city}/with_comments',
  87.                     ['city' => $city->getId()],
  88.                     max(1, (int) $request->attributes->get('page'1)),
  89.                     $topPlacement
  90.                 );
  91.                 $recommendationsFill = [
  92.                     'profiles' => $result,
  93.                     'applied' => false,
  94.                     'original_count' => $result instanceof Page $result->totalCount() : 0,
  95.                 ];
  96.                 if ($result instanceof Page) {
  97.                     $recommendationsFill $this->profileListingRecommendationsFiller->fill($city$result$specs->genders());
  98.                 }
  99.                 $form $this->createForm(ProfileFilterForm::class, $formData, [
  100.                     'action' => $this->generateUrl('profile_filters.filter', ['city' => $city->getUriIdentity()]),
  101.                     'csrf_protection' => false,
  102.                     'form_data' => $formData,
  103.                     'profiles_presence_by_filters' => $presence,
  104.                 ]);
  105.                 return $this->prepareForXhr($this->render('ProfileList/profile_filter.profiles.partial.html.twig', [
  106.                     'profiles' => $recommendationsFill['profiles'],
  107.                     'recommendationSpec' => \App\Specification\ElasticSearch\ProfileIsLocated::withinCity($city),
  108.                     'recommendations_fill_applied' => $recommendationsFill['applied'],
  109.                     'recommendations_fill_original_count' => $recommendationsFill['original_count'],
  110.                     'show_pagination' => true,
  111.                     'profiles_presence_by_filters' => $presence,
  112.                     'profile_filter_form' => $form->createView(),
  113.                 ]));
  114.             } catch (\Exception) {
  115.                 // Fall back to the regular DB-backed filter path below.
  116.             }
  117.         }
  118.         $result $profilesFilterService->filter($city$listingTypeName$formData->filters$specs->spec(), $specs->additionalSpecs(), $specs->genders());
  119.         $presence $profilesFilterService->profilesPresenceByFilters();
  120.         $recommendationsFill = [
  121.             'profiles' => $result,
  122.             'applied' => false,
  123.             'original_count' => $result instanceof Page $result->totalCount() : 0,
  124.         ];
  125.         if ($result instanceof Page) {
  126.             $recommendationsFill $this->profileListingRecommendationsFiller->fill($city$result$specs->genders());
  127.         }
  128.         $form $this->createForm(ProfileFilterForm::class, $formData, [
  129.             'action' => $this->generateUrl('profile_filters.filter', ['city' => $city->getUriIdentity()]),
  130.             'csrf_protection' => false,
  131.             'form_data' => $formData,
  132.             'profiles_presence_by_filters' => $presence,
  133.         ]);
  134.         return $this->prepareForXhr($this->render('ProfileList/profile_filter.profiles.partial.html.twig', [
  135.             'profiles' => $recommendationsFill['profiles'],
  136.             'recommendationSpec' => \App\Specification\ElasticSearch\ProfileIsLocated::withinCity($city),
  137.             'recommendations_fill_applied' => $recommendationsFill['applied'],
  138.             'recommendations_fill_original_count' => $recommendationsFill['original_count'],
  139.             'show_pagination' => true,
  140.             'profiles_presence_by_filters' => $presence,
  141.             'profile_filter_form' => $form->createView(),
  142.         ]));
  143.     }
  144.     private function shouldUseOriginalListingSource(ProfileFilterFormData $formData): bool
  145.     {
  146.         return 'listWithComments' === $formData->listing && $this->filtersAreEmpty($formData->filters);
  147.     }
  148.     private function filtersAreEmpty(ProfileFilterFormDataFilters $filters): bool
  149.     {
  150.         foreach ($filters as $value) {
  151.             if (is_array($value)) {
  152.                 if (!$this->arrayHasOnlyEmptyValues($value)) {
  153.                     return false;
  154.                 }
  155.                 continue;
  156.             }
  157.             if (false !== $value && null !== $value) {
  158.                 return false;
  159.             }
  160.         }
  161.         return true;
  162.     }
  163.     private function arrayHasOnlyEmptyValues(array $values): bool
  164.     {
  165.         foreach ($values as $value) {
  166.             if (null !== $value && '' !== $value) {
  167.                 return false;
  168.             }
  169.         }
  170.         return true;
  171.     }
  172. }