<?php
/**
* Created by simpson <simpsonwork@gmail.com>
* Date: 2019-04-15
* Time: 19:51
*/
namespace App\Controller;
use AngelGamez\PorpaginasBundle\Controller\PaginationTrait;
use App\Entity\Location\City;
use App\Repository\DistrictRepository;
use App\Repository\SaloonRepository;
use App\Service\CountryCurrencyResolver;
use App\Service\Features;
use App\Service\ProfileListingRecommendationsFiller;
use App\Service\ResponsiveAssetsService;
use App\Specification\QueryModifier\FreeProfilesFeatureSaloonOrder;
use App\Specification\Saloon\SaloonIsNotHidden;
use App\Specification\QueryModifier\SaloonOrderedByStatus;
use App\Specification\Saloon\SaloonInMoskowDistricts;
use App\Specification\Saloon\SaloonIsActive;
use App\Specification\Saloon\SaloonIsLocated;
use App\Specification\Saloon\SaloonIsVip;
use Flagception\Bundle\FlagceptionBundle\Annotations\Feature;
use Happyr\DoctrineSpecification\Spec;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use OpenApi\Attributes as OA;
use Porpaginas\Page;
class SaloonListController extends AbstractController
{
use PaginationTrait;
use ResponseTrait;
const ENTRIES_ON_PAGE = 36;
private mixed $perPage;
public function __construct(
private SaloonRepository $saloonRepository,
private DistrictRepository $districtRepository,
private Features $features,
private RequestStack $requestStack,
private ResponsiveAssetsService $responsiveAssetsService,
private ProfileListingRecommendationsFiller $profileListingRecommendationsFiller,
ParameterBagInterface $parameterBag
)
{
$this->perPage = $parameterBag->get('saloon_list.per_page');
}
/**
* @Feature("has_saloons")
*/
#[ParamConverter('city', converter: 'city_converter')]
#[Route("/api/saloons/listing/city/{city}", name: "api.saloon_listing.by_city", methods: "GET", format: "json")]
#[OA\Parameter(name: "page", in: "query", schema: new OA\Schema(type: "integer", default: 1, minimum: 1))]
#[OA\Tag(name: "SaloonListing")]
#[OA\Response(
response: 200,
description: '',
content: new OA\JsonContent(ref: "#/components/schemas/SaloonListingPage")
)]
public function listByCity(Request $request, City $city): Response
{
$criteria = Spec::andX(
$this->features->free_profiles() ? new SaloonIsNotHidden() : new SaloonIsActive(),
SaloonIsLocated::withinCity($city),
$this->features->free_profiles() ? new FreeProfilesFeatureSaloonOrder() : new SaloonOrderedByStatus()
);
$result = $this->saloonRepository->matchingSpec($criteria);
$saloons = $this->takePage($result, $this->perPage);
$recommendationsFill = $this->getRecommendationsFill($city, $saloons);
if ($this->isApiRequest($request)) {
return $this->json($saloons, context: ['groups' => ['listing']]);
}
return $this->render('SaloonList/list.html.twig', [
'saloons' => $saloons,
'recommended_profiles' => $recommendationsFill['profiles'],
'ssr_recommended_profiles' => $recommendationsFill['ssr_profiles'],
'recommendations_fill_applied' => $recommendationsFill['applied'],
'recommendations_fill_original_count' => $recommendationsFill['original_count'],
]);
}
/**
* @Feature("has_saloons")
*/
#[ParamConverter('city', converter: 'city_converter')]
public function listForVipRelax(CountryCurrencyResolver $countryCurrencyResolver, Request $request, City $city): Response
{
$minPrice = $countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
'RUB' => 4000,
'UAH' => 1200,
'USD' => 100,
'EUR' => 100,
]);
$districts = [];
foreach (SaloonInMoskowDistricts::$districtsUri as $uri) {
if (null !== $district = $this->districtRepository->ofUriIdentityWithinCity($uri, $city)) {
$districts[] = $district;
}
}
if (!empty($districts)) {
$criteria = Spec::andX(
$this->features->free_profiles() ? new SaloonIsNotHidden() : new SaloonIsActive(),
SaloonIsLocated::withinCity($city),
new SaloonIsVip($city, $districts, $minPrice),
$this->features->free_profiles() ? new FreeProfilesFeatureSaloonOrder() : new SaloonOrderedByStatus()
);
$result = $this->saloonRepository->matchingSpec($criteria);
$saloons = $this->takePage($result, $this->perPage);
} else {
$saloons = $this->emptyPagination();
}
$recommendationsFill = $this->getRecommendationsFill($city, $saloons);
return $this->render('SaloonList/list.html.twig', [
'saloons' => $saloons,
'recommended_profiles' => $recommendationsFill['profiles'],
'ssr_recommended_profiles' => $recommendationsFill['ssr_profiles'],
'recommendations_fill_applied' => $recommendationsFill['applied'],
'recommendations_fill_original_count' => $recommendationsFill['original_count'],
]);
}
private function getRecommendationsFill(City $city, Page $saloons): array
{
$fill = $this->profileListingRecommendationsFiller->recommendedProfilesForPage($city, $saloons);
$fill['ssr_profiles'] = !$fill['applied']
? $this->profileListingRecommendationsFiller->popularProfilesForBlock($city, $saloons)
: [];
return $fill;
}
protected function render(string $view, array $parameters = [], Response $response = null): Response
{
if($this->requestStack->getCurrentRequest()->getMethod() == 'POST') {
$response = parent::render('SaloonList/list.saloons.html.twig', $parameters, $response);
$content = preg_replace('/\s{2,}/', ' ', $response->getContent());
$response->setContent($content);
return $response;
} else {
return parent::render($view, $parameters, $response);
}
}
}