<?php
namespace App\Service;
use App\Entity\Complex;
use App\Entity\Hotel;
use App\Entity\Order;
use App\Entity\Page;
use App\Entity\Reporting;
use App\Entity\RoomReserve;
use App\Entity\User;
use App\Security\User as SecurityUser;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Security;
class HotelHelper
{
public const SESSION_CURRENT_HOTEL_KEY = 'currentHotel';
private Security $security;
private RequestStack $requestStack;
private EntityManagerInterface $em;
private ?Hotel $hotel;
private array $hotels;
private array $reportings;
public function __construct(
Security $security,
RequestStack $requestStack,
EntityManagerInterface $em
) {
$this->security = $security;
$this->requestStack = $requestStack;
$this->em = $em;
$this->hotel = null;
$this->hotels = [];
$this->reportings = [];
}
public function getEntityManager(): EntityManagerInterface
{
return $this->em;
}
public function getHotels(?User $user): array
{
if (!$user) {
return [];
}
if (empty($this->hotels)) {
if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
$this->hotels = $this->em->getRepository(Hotel::class)->findAll();
} else {
$this->hotels = $this->getUserHotels($user);
}
}
return $this->hotels;
}
public function getUserHotels(?User $user): array
{
if (!$user) {
return [];
}
$hotels = [];
foreach ($user->getAssignedHotels() as $assignedHotel) {
$hotelId = is_object($assignedHotel->getId()) ? $assignedHotel->getId()->__toString() : $assignedHotel->getId();
$hotels[$hotelId] = $assignedHotel;
}
foreach ($user->getHotels() as $hotel) {
$hotelId = is_object($hotel->getId()) ? $hotel->getId()->__toString() : $hotel->getId();
if (array_key_exists($hotelId, $hotels)) {
continue;
}
$hotels[] = $hotel;
}
usort($hotels, static fn(Hotel $a, Hotel $b) => strnatcasecmp($a->getName(), $b->getName()));
return array_values($hotels);
}
public function getReportings(?User $user): array
{
if (!$user) {
return [];
}
if (empty($this->reportings)) {
if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
$this->reportings = $this->em->getRepository(Reporting::class)->findAllByCurrentHotel();
} else {
$this->reportings = $this->getUserReportings($user);
}
}
return $this->reportings;
}
public function getUserReportings(?User $user): array
{
if (!$user) {
return [];
}
$reportings = [];
foreach ($this->em->getRepository(Reporting::class)->findAllByCurrentHotel() as $reporting) {
if ($this->security->isGranted('ACL_VIEW', $reporting)) {
$reportings[] = $reporting;
}
}
return array_values($reportings);
}
public function userCanAccessToComplex(?User $user, ?Complex $complex): bool
{
if (!$user || !$complex) {
return false;
}
if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
return true;
}
$complexHotels = $complex->getHotels()->toArray();
$userHotels = $this->getUserHotels($user);
return !empty(array_intersect($complexHotels, $userHotels));
}
public function userCanAccessToHotel(?User $user, ?Hotel $hotel): bool
{
if (!$user || !$hotel) {
return false;
}
if ($this->security->isGranted('ROLE_SUPER_ADMIN')) {
return true;
}
return !empty(
array_filter($this->getUserHotels($user), static function (Hotel $hotelItem) use ($hotel) {
return $hotelItem->getId() === $hotel->getId();
})
);
}
public function setCurrentHotel(Hotel $hotel): void
{
$this->hotel = $hotel;
$this->requestStack->getSession()->set(self::SESSION_CURRENT_HOTEL_KEY, $hotel);
}
public function getCurrentHotel($user, Complex $complex = null): ?Hotel
{
if ($this->hotel) {
return $this->hotel;
}
$sessionHotel = $this->requestStack->getSession()->get(self::SESSION_CURRENT_HOTEL_KEY);
if ($sessionHotel) {
$this->hotel = $this->em->getRepository(Hotel::class)->find($sessionHotel->getId());
return $this->hotel;
}
// Get the guests Hotel from the RoomReserve ID in \App\Security\User instead of \App\Entity\User
if ($user instanceof SecurityUser) {
$roomReserve = $this->em->getRepository(RoomReserve::class)->findOneBy(['id' => $user->getRoomReserveId()]); // Don't inject RoomReserveRepository because of circular reference
if ($roomReserve && $roomReserve->getRoom()) {
return $roomReserve->getRoom()->getHotel();
}
return null;
}
if (!$user) {
$user = $this->security->getUser();
}
$hotels = $this->getHotels($user);
if (empty($hotels)) {
return null;
}
if (!is_null($complex)) {
$complexHotels = $complex->getHotels()->toArray();
$commonHotels = array_intersect($hotels, $complexHotels);
if (count($commonHotels) === 0) {
return null;
}
$hotels = $commonHotels;
}
$this->hotel = array_pop($hotels);
return $this->hotel;
}
public function rootPages(?SecurityUser $user): ArrayCollection
{
if (empty($user)) {
return new ArrayCollection();
}
$currentHotel = $this->getCurrentHotel($user);
if (!$currentHotel) {
return new ArrayCollection();
}
/** @var RoomReserve $roomReserve */
$roomReserve = $this->em->getRepository(RoomReserve::class)->findOneBy(['id' => $user->getRoomReserveId()]);
if (!$roomReserve) {
return new ArrayCollection();
}
$rootPages = $currentHotel->getPages()->filter(function(Page $page) use ($roomReserve) {
return !$page->isDeleted() && $page->getParent() === null && ($page->getTourOperators()->isEmpty() || $page->getTourOperators()->contains($roomReserve->getTourOperator()));
})->toArray();
return new ArrayCollection($rootPages);
}
public function menuPages(?SecurityUser $user): ArrayCollection
{
if (empty($user)) {
return new ArrayCollection();
}
$currentHotel = $this->getCurrentHotel($user);
if (!$currentHotel) {
return new ArrayCollection();
}
/** @var RoomReserve $roomReserve */
$roomReserve = $this->em->getRepository(RoomReserve::class)->findOneBy(['id' => $user->getRoomReserveId()]);
if (!$roomReserve) {
return new ArrayCollection();
}
$menuPages = $currentHotel->getPages()->filter(function(Page $page) use ($roomReserve) {
return !$page->isDeleted() && $page->getShowMenu() === true && ($page->getTourOperators()->isEmpty() || $page->getTourOperators()->contains($roomReserve->getTourOperator()));
})->toArray();
return new ArrayCollection($menuPages);
}
public function getOrder(): ?Order
{
$orderId = $this->requestStack->getSession()->get('orderId');
if (!empty($orderId)) {
$order = $this->em->getRepository(Order::class)->find($orderId); // Don't inject OrderRepository because of circular reference
if (!empty($order)) {
return $order;
}
}
return null;
}
public function getOrderItemsAmount(): int
{
$order = $this->getOrder();
$totalAmount = 0;
if ($order && !$order->getOrderItems()->isEmpty()) {
foreach ($order->getOrderItems() as $orderItem) {
$totalAmount += $orderItem->getAmount();
}
}
return $totalAmount;
}
public function getUserById($id): ?User
{
$user = $this->em->getRepository(User::class)->find($id);
$userClass = ClassUtils::getRealClass(get_class($user));
return $userClass === User::class? $user : null;
}
}