Files
SomniaRooms/src/Controller/SearchRoomsController.php
T

191 lines
6.4 KiB
PHP

<?php
namespace App\Controller;
use App\ApiErrorException;
use App\Consts\ConfigVariableConsts;
use App\DTO\ApiErrorMessage;
use App\Repository\RoomAvailabilityRepository;
use App\Repository\RoomCategoryRepository;
use App\Request\SearchPeriodRequest;
use App\Response\SearchAvailabilityResponse;
use App\Request\SearchPricesForCategoryRequest;
use App\Response\SearchPricesResponse;
use App\Response\SearchPricesResponsePriceItem;
use App\Service\ConfigVariableService;
use App\Service\PricesService;
use DateTimeInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Attribute\Route;
use OpenApi\Attributes as OA;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload;
class SearchRoomsController extends AbstractController
{
private string $configMaxAllowedNightAmount;
public function __construct(
private ConfigVariableService $configVarService,
private LoggerInterface $logger
) {
$this->configMaxAllowedNightAmount = $configVarService->getVariableFromConst(ConfigVariableConsts::CONFIG_API_NAXNIGHTS)->getValue();
}
/**
* Get availability for all rooms on period.
* For each room, the minimal availability will be returned.
*/
#[Route('/api/search/availability', name: 'app_search_availability', methods: ["POST"], format: "json")]
#[OA\Tag(name: "Searchs")]
#[OA\Response(
response: 200,
description: 'Each room available',
content: new OA\JsonContent(
type: 'object',
properties: [
new OA\Property(
property: "results",
type: "array",
items: new OA\Items(ref: new Model(type: SearchAvailabilityResponse::class))
)
]
)
)]
#[OA\RequestBody(
content: new OA\JsonContent(
type: 'object',
ref: new Model(type: SearchPeriodRequest::class),
)
)]
public function getAvailabilityForPeriod(
RoomAvailabilityRepository $repoAvailability,
#[MapRequestPayload()] SearchPeriodRequest $searchRequest
): JsonResponse {
$datesValid = $this->areRequestDatesValid($searchRequest->startDate, $searchRequest->endDate);
if ($datesValid != null) {
throw $datesValid;
}
$rs = $repoAvailability->getAvailabilityForPeriod($searchRequest->startDate, $searchRequest->endDate);
return $this->json(["results" => $rs]);
}
/**
* Get the price of each room on each day of a period.
*
*/
#[Route('/api/search/prices', name: 'app_search_prices', methods: ["POST"], format: "json")]
#[OA\Tag(name: "Searchs")]
#[OA\RequestBody(
content: new OA\JsonContent(
type: 'object',
ref: new Model(type: SearchPeriodRequest::class),
)
)]
#[OA\Response(
response: 200,
description: 'Total Prices for the period of each room',
content: new OA\JsonContent(
type: 'object',
properties: [
new OA\Property(
property: "results",
type: "array",
items: new OA\Items(ref: new Model(type: SearchPricesResponse::class))
)
]
)
)]
public function getPricesForPeriod(
PricesService $priceService,
#[MapRequestPayload()] SearchPeriodRequest $searchRequest
): JsonResponse {
$datesValid = $this->areRequestDatesValid($searchRequest->startDate, $searchRequest->endDate);
if ($datesValid != null) {
throw $datesValid;
}
$rs = $priceService->getRoomSearch($searchRequest->startDate, $searchRequest->endDate);
return $this->json(["results" => $rs]);
}
/**
* Get room category price for given period.
* Returns price for a room category.
* This price is the total for all the selected days by guest number.
*/
#[Route('/api/search/pricesCategory', name: 'app_search_pricesForCategory', methods: ["POST"], format: "json")]
#[OA\Tag(name: "Searchs")]
#[OA\Response(
response: 200,
description: 'Room price by guest number',
content: new OA\JsonContent(
type: 'object',
properties: [
new OA\Property(
property: "results",
type: "array",
items: new OA\Items(ref: new Model(type: SearchPricesResponsePriceItem::class))
)
]
)
)]
#[OA\RequestBody(
content: new OA\JsonContent(
type: 'object',
ref: new Model(type: SearchPricesForCategoryRequest::class),
)
)]
public function getPricesForCategoryOnPeriod(
RoomCategoryRepository $repoCat,
PricesService $priceService,
#[MapRequestPayload()] SearchPricesForCategoryRequest $searchRequest
): JsonResponse {
$datesValid = $this->areRequestDatesValid($searchRequest->startDate, $searchRequest->endDate);
if ($datesValid != null) {
throw $datesValid;
}
$roomCategory = $repoCat->find($searchRequest->roomCategory);
if ($roomCategory === null) {
throw new ApiErrorException(
new ApiErrorMessage(422, ApiErrorMessage::TYPE_VALIDATION_ERROR),
'Invalid RoomCategory: ' . $searchRequest->roomCategory,
);
}
$rs = $priceService->getFinalPricesForSearch($roomCategory, $searchRequest->startDate, $searchRequest->endDate);
return $this->json(["results" => $rs]);
}
private function areRequestDatesValid(DateTimeInterface $dateStart, DateTimeInterface $dateEnd): ApiErrorException|null
{
if ($dateStart >= $dateEnd) {
return new ApiErrorException(
new ApiErrorMessage(422, ApiErrorMessage::TYPE_INVALID_DATE),
'startDate cant be before endDate',
);
}
$daysDiff = $dateStart->diff($dateEnd)->days;
if ($daysDiff > $this->configMaxAllowedNightAmount) {
return new ApiErrorException(
new ApiErrorMessage(400, ApiErrorMessage::TYPE_API_LIMIT),
'Query exceeded max allowed night amount',
);
}
return null;
}
}