<?php
declare(strict_types=1);
namespace App\Helper\Cruise;
use App\Controller\Website\ListController;
use App\Helper\Partner\PartnerHelper;
use App\Helper\SuluHelper;
use App\Repository\Cabin\CabinTypeRepository;
use App\Repository\Itinerary\StopoverRepository;
use Crea\MediaBundle\Entity\Enum\MediaFamilyCodeEnum;
use Crea\MediaBundle\Entity\MediaFile;
use Crea\MediaBundle\Helper\MediaTagQueryHelper;
use Croisiland\CommonBundle\Entity\Cabin\CabinType;
use Croisiland\CommonBundle\Entity\Company\Company;
use Croisiland\CommonBundle\Entity\Cruise\Cruise;
use Croisiland\CommonBundle\Entity\Itinerary\DestinationMain;
use Croisiland\CommonBundle\Entity\Itinerary\DestinationSecondary;
use Croisiland\CommonBundle\Entity\Itinerary\Stopover;
use Croisiland\CommonBundle\Entity\Partner\Partner;
use Croisiland\CommonBundle\Entity\Ship\Ship;
use Croisiland\CommonBundle\Entity\Tag\Tag;
use Croisiland\CommonBundle\Model\CruiseSearchModel;
use Croisiland\CommonBundle\Serializer\CruiseSearchModelSerializer;
use Croisiland\CommonBundle\Service\CruiseSearchService;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Random\RandomException;
class CruiseHelper
{
public function __construct(
private readonly CruiseSearchService $cruiseSearchService,
private readonly CruiseSearchModelSerializer $cruiseSearchModelSerializer,
private MediaTagQueryHelper $mediaTagQueryHelper,
private StopoverRepository $stopoverRepository,
private CabinTypeRepository $cabinTypeRepository,
private PartnerHelper $partnerHelper,
private SuluHelper $suluHelper,
) {
}
/**
* @param array<object> $searchElements available objects : Companies, Ship, Tags, Partner,
* @param int $limit default 5
* @param bool $random default false
* @return Cruise[]
*
* @throws NoResultException
* @throws NonUniqueResultException
*/
public function searchCruises(array $searchElements, int $limit = 5, bool $random = false): array
{
$model = $this->getCruiseSearchModelFromSearchElements($searchElements);
if (null === $model->getPartner()){
$partner = $this->partnerHelper->getCurrentPartner();
if ($partner){
$model->setPartner($partner);
}
}
$model->setPerPage($limit);
$model->setRandomized($random);
$result = $this->cruiseSearchService->search($model);
return $result['paginated_result'];
}
/**
* Génère une URL de liste de croisières avec des paramètres de recherche.
*
* @param array<object> $searchElements available objects : Companies, Ship, Tags, Partner,
* @param string|null $locale Locale. Si null, utilise la locale actuelle.
* @param string|null $webspaceKey Clé du webspace. Si null, utilise le webspace actuel.
* @param string|null $domain Domaine personnalisé. Si null, utilise le domaine actuel.
* @param string|null $scheme Schéma (ex: 'https'). Si null, utilise le schéma actuel.
* @param bool $withoutDomain Si true, retourne une URL relative (sans domaine).
*
* @return string URL générée avec paramètres GET.
*/
public function getCruiseSearchUrl(
array $searchElements,
?string $locale = null,
?string $webspaceKey = null,
?string $domain = null,
?string $scheme = null,
bool $withoutDomain = true): string
{
$model = $this->getCruiseSearchModelFromSearchElements($searchElements);
if (null === $model->getPartner()){
$partner = $this->partnerHelper->getCurrentPartner();
if ($partner){
$model->setPartner($partner);
}
}
$queryParameters = $this->cruiseSearchModelSerializer->toQueryParameters($model);
return $this->suluHelper->generateUrlWithQueryParams(
ListController::BASE_PATH,
$queryParameters,
$locale,
$webspaceKey,
$domain,
$scheme,
$withoutDomain
);
}
/**
* @param array<object> $searchElements available objects : Companies, Ship, Tags, DestinationMain, DestinationSecondary,
*/
private function getCruiseSearchModelFromSearchElements(array $searchElements): CruiseSearchModel
{
// TODO update with adder and removers in the CruiseSearchModel
$model = new CruiseSearchModel();
foreach ($searchElements as $element) {
if ($element instanceof Company) {
$model->addCompany($element);
}
if ($element instanceof Ship) {
$model->addShip($element);
}
if ($element instanceof Tag) {
$model->addTag($element);
}
if ($element instanceof DestinationMain) {
$model->addDestinationMain($element);
}
if ($element instanceof DestinationSecondary) {
$model->addDestinationSecondary($element);
}
if ($element instanceof Stopover) {
$model->addDeparturePort($element);
}
}
return $model;
}
/**
* Retourne un tableau contenant l'objet à afficher et le nom de la classe en minuscule, utilisable pour concatener avec le nom du template
* @return array{
* subject: null|DestinationSecondary|Ship|DestinationMain|Company,
* template: null|string
* }
*/
public function getSearchMainSubjectInfos(CruiseSearchModel $searchModel): array
{
$result = [
'subject' => null,
'template' => null,
];
$collections = [
// TODO $searchModel->getOffers()
$searchModel->getDestinationsSecondary(),
$searchModel->getShips(),
$searchModel->getDestinationsMain(),
$searchModel->getCompanies(),
];
foreach ($collections as $collection) {
if (!$collection->isEmpty()) {
$lowest = null;
foreach ($collection as $item) {
/** @var DestinationSecondary|Ship|DestinationMain|Company $item */
if ($lowest === null || $item->getListOrder() < $lowest->getListOrder()) {
$lowest = $item;
}
}
$result['subject'] = $lowest;
$className = explode('\\', get_class($lowest));
$result['template'] = mb_convert_case(end($className), MB_CASE_LOWER, "UTF-8");
}
}
return $result;
}
/**
* @param Cruise $cruise
* @return array{
* ship: MediaFile[],
* stopovers: MediaFile[],
* cabinTypes: MediaFile[]
* }
* @throws RandomException
*/
public function getCruiseRelatedMedias(Cruise $cruise): array
{
// get media from Ship no tags, only Images, not random
$shipMedias = $this->mediaTagQueryHelper->getMedias([], $cruise->getShip(), MediaFamilyCodeEnum::FAM_IMAGE, true);
// get media from each itinerary stopovers no tags, only Images, not random
$stopoversMedias = [];
foreach ($this->stopoverRepository->findStopoversForCruise($cruise) as $stopover) {
$stopoversMedias = array_merge(
$stopoversMedias,
$this->mediaTagQueryHelper->getMedias([], $stopover, MediaFamilyCodeEnum::FAM_IMAGE, true)
);
}
// get media from each cruise cabinTypes no tags, only Images, not random
$cabinTypesMedias = [];
foreach ( $this->cabinTypeRepository->getCabinTypesForCruise($cruise) as $cabinType ) {
$cabinTypesMedias = array_merge(
$cabinTypesMedias,
$this->mediaTagQueryHelper->getMedias([], $cabinType, MediaFamilyCodeEnum::FAM_IMAGE, true)
);
}
return [
'ship' => $shipMedias,
'stopovers' => $stopoversMedias,
'cabinTypes' => $cabinTypesMedias,
];
}
}