Files
myep/src/BusProNet/Model/Travel.php
T

232 lines
7.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\BusProNet\Model;
use App\BusProNet\Constants;
use App\BusProNet\Traits\SortByPriceTrait;
use Symfony\Component\Serializer\Attribute\Context;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
/**
* Represents a travel package with services, accommodation, and pricing information.
*
* This class handles travel data including dates, hotel information, available services,
* transportation options, and participant configuration. It provides methods to filter
* and retrieve services by various criteria and manage included services.
*/
class Travel
{
use SortByPriceTrait;
#[Groups(['api:list', 'api:single'])]
public ?int $id = null;
#[Groups(['api:list', 'api:single'])]
public ?string $code = null;
#[Groups(['api:list', 'api:single'])]
public ?string $label = null;
#[Groups(['api:list', 'api:single'])]
public ?int $hotelId = null;
#[Groups(['api:single'])]
public ?Hotel $hotel = null;
#[Groups(['api:list', 'api:single'])]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
public ?\DateTimeImmutable $dateFrom = null;
#[Groups(['api:list', 'api:single'])]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
public ?\DateTimeImmutable $dateTo = null;
#[Groups(['api:list', 'api:single'])]
public ?string $type = null;
#[Groups(['api:list', 'api:single'])]
public ?float $priceFrom = null;
#[Groups(['api:single'])]
public array $selectionGroups = [];
#[Groups(['api:single'])]
public array $additionalServices = [];
#[Groups(['api:single'])]
public bool $additionalServicesMutable = true;
#[Groups(['api:single'])]
public array $transportationServices = [];
#[Groups(['api:single'])]
public bool $transportationServicesMutable = true;
#[Groups(['api:single'])]
public array $pickupsOutbound = [];
#[Groups(['api:single'])]
public array $pickupsInbound = [];
#[Groups(['api:single'])]
public bool $pickupsMutable = true;
#[Groups(['api:single'])]
public array $rooms = [];
#[Groups(['api:single'])]
public bool $roomsMutable = true;
#[Groups(['api:single'])]
public bool $participantDataMutable = true;
#[Groups(['api:single'])]
public bool $participantCountMutable = true;
#[Groups(['api:single'])]
public ?Guide $guide = null;
/**
* @var array<Insurance> Available insurances for this travel package
*/
#[Groups(['api:single'])]
public array $insurances = [];
/**
* Retrieves additional services filtered by subtype, availability, and optionally by travel date range.
*
* Filters additional services based on the provided subtype(s), availability,
* and optionally whether their date range overlaps with the travel dates.
* Services with null dates are considered always available when date filtering is enabled.
* Services are sorted by price in ascending order.
*
* @param mixed $subTypes The service subtype(s) to filter by
* @param bool $filterAvailable Whether to include only available services
* @param bool $filterByTravelDateRange Whether to filter by travel date range overlap
*
* @return array<int, Service> The filtered and sorted services array
*/
public function getAdditionalServicesBySubTypes(mixed $subTypes, bool $filterAvailable = true, bool $filterByTravelDateRange = false): array
{
$subTypes = (array) $subTypes;
$services = array_filter($this->additionalServices, function (Service $service) use ($subTypes, $filterAvailable, $filterByTravelDateRange) {
// Check subtype
if (false === in_array($service->subType, $subTypes)) {
return false;
}
// Check availability
if (true === $filterAvailable && null !== $service->available && 0 >= $service->available) {
return false;
}
// Check date range overlap if filtering by travel dates is enabled
if (true === $filterByTravelDateRange) {
if (null !== $service->dateFrom && null !== $service->dateTo
&& null !== $this->dateFrom && null !== $this->dateTo) {
// Service is available if its date range overlaps with travel dates:
// service.dateFrom <= travel.dateTo AND service.dateTo >= travel.dateFrom
return $service->dateFrom <= $this->dateTo && $service->dateTo >= $this->dateFrom;
}
// Service is available if it has no date constraints or travel has no dates
}
return true;
});
return $this->sortByPrice($services);
}
/**
* Retrieves transportation services filtered by direction and availability.
*
* Filters transportation services based on travel direction and optionally
* by availability. Services are sorted by subtype.
*
* @param string $direction The travel direction to filter by
* @param bool $filterAvailable Whether to include only available services
*
* @return array<int, Service> The filtered and sorted transportation services
*/
public function getTransportationServicesByDirection(string $direction, bool $filterAvailable = true): array
{
$services = array_filter($this->transportationServices, function (Service $service) use ($direction, $filterAvailable) {
return $direction === $service->direction
&& (false === $filterAvailable || $service->available > 0 || null === $service->available);
});
usort($services, function (Service $a, Service $b) {
return $a->subType <=> $b->subType;
});
return $services;
}
/**
* Retrieves included services from selection groups.
*
* Maps selection group IDs to their corresponding services based on
* the predefined included services mapping.
*
* @return array<int, Service> The included services from selection groups
*/
public function getIncludedServices(): array
{
$services = [];
foreach (CrmSelectionGroup::$includedServicesMapping as $id => $label) {
if (true === isset($this->selectionGroups[$id])) {
$services[] = $this->selectionGroups[$id];
}
}
return $services;
}
/**
* Retrieves rooms filtered by their IDs.
*
* Filters the rooms array to return only rooms whose IDs match
* the provided array of IDs. Returns an empty array if no matching
* rooms are found.
*
* @param array<int> $ids The array of room IDs to filter by
*
* @return array<int, Room> The filtered rooms array
*/
public function getRoomsByIds(array $ids): array
{
if (true === empty($ids)) {
return [];
}
return array_filter($this->rooms, function (Room $room) use ($ids) {
return in_array($room->id, $ids, true);
});
}
/**
* Retrieves all available rooms for booking.
*
* Filters the rooms collection to return only rooms that have availability
* greater than zero and have an available status. This ensures only
* bookable rooms are returned for selection.
*
* @return array<int, Room> The filtered array of available rooms, indexed by room ID
*/
public function getAvailableRooms(): array
{
$result = [];
foreach ($this->rooms as $room) {
if ($room->available > 0 && Constants::STATUS_AVAILABLE === $room->status) {
$result[$room->id] = $room;
}
}
return $result;
}
}