src/Controller/BuildingController.php line 55
<?php
namespace App\Controller;
use App\Entity\Building;
use App\Entity\City;
use App\Entity\HousingCertificate;
use App\Services\GoogleMapsService;
use Symfony\Contracts\Translation\TranslatorInterface;
use App\Entity\User;
use App\Entity\BuildingDocument;
use App\Entity\BuildingEquipment;
use App\Entity\Residence;
use App\Entity\WantedVisio;
use App\Entity\Invoice;
use App\Form\BuildingAddFormType;
use App\Form\BuildingEditFormType;
use App\Repository\BuildingRepository;
use App\Repository\BuildingDocumentRepository;
use App\Repository\HousingCertificateRepository;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use App\Repository\CityRepository;
use App\Repository\LikedBuildingRepository;
use App\Entity\LastViewedBuilding;
use App\Services\Auth\UserAuthService;
use App\Services\Mails\Mails;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Imagine\Gd\Imagine;
use Imagine\Image\Box;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Psr\Log\LoggerInterface;
class BuildingController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private BuildingRepository $buildingRepository,
private HousingCertificateRepository $housingCertificateRepository,
private UserAuthService $authService,
private GoogleMapsService $googleMapsService,
private LoggerInterface $logger // Inject the logger
) {}
#[Route(path: ["fr" => "/building/{id}", "en" => "/en/building/{id}"], name: 'detail_building')]
public function index(
Building $building,
LikedBuildingRepository $likedBuildingRepository,
BuildingDocumentRepository $buildingDocumentRepository,
SessionInterface $session
): Response {
if (!$building->getIsActive() && ((!$this->getUser()) || ($this->getUser() != $building->getPropertyManager() && !in_array('ROLE_ADMIN', $this->getUser()->getRoles())))) {
return $this->render('building/not_actif.html.twig');
}
$currentUser = $this->getUser();
if ($currentUser && in_array("ROLE_TENANT", $currentUser->getRoles())) {
$existing = $this->entityManager->getRepository(\App\Entity\LastViewedBuilding::class)
->findOneBy(['user' => $currentUser, 'building' => $building]);
if (!$existing) {
$lastViewed = new \App\Entity\LastViewedBuilding();
$lastViewed->setUser($currentUser);
$lastViewed->setBuilding($building);
$lastViewed->setViewedAt(new \DateTimeImmutable());
$this->entityManager->persist($lastViewed);
} else {
$existing->setViewedAt(new \DateTimeImmutable());
}
$this->entityManager->flush();
}
if ($currentUser) {
$lastViewedBuildings = $session->get('lastViewedBuildings', []);
if (!in_array($building->getId(), array_column($lastViewedBuildings, 'id'))) {
if (count($lastViewedBuildings) >= 2) {
array_shift($lastViewedBuildings);
}
$lastViewedBuildings[] = ['id' => $building->getId(), 'createdAt' => new \DateTime()];
$session->set('lastViewedBuildings', $lastViewedBuildings);
}
}
$canRequestVisio = true;
if ($this->getUser() && $this->getUser()->getWantedVisios()) {
foreach ($this->getUser()->getWantedVisios() as $wantedVisio) {
if ($wantedVisio->getBuilding() === $building) {
$now = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Paris'));
$diff = $now->diff($wantedVisio->getCreatedAt());
if ($diff->h < 24) {
$canRequestVisio = false;
}
}
}
}
$allowEdit = false;
if (!is_null($this->getUser())) {
if (in_array("ROLE_ADMIN", $this->getUser()->getRoles())) {
$allowEdit = true;
} elseif ($building->getPropertyManager() == $this->getUser()) {
$allowEdit = true;
}
}
$liked = $likedBuildingRepository->findOneBy(['user' => $this->getUser(), 'building' => $building]);
$documents = $buildingDocumentRepository->findBy(['complexPropertyId' => $building->getComplexPropertyId()]);
$buildingsInComplex = $this->buildingRepository->findByComplexPropertyId($building->getComplexPropertyId());
$similarProperties = $this->buildingRepository->findSimilarProperties(
$building->getCityEntity()->getCity(),
$building->getSurface(),
$building->getRent(),
$building->getComplexPropertyId(),
$building->getId()
);
foreach ($buildingsInComplex as $complexBuilding) {
$complexBuilding->getBuildingDocuments()->initialize();
}
$lowestRent = null;
foreach ($buildingsInComplex as $complexBuilding) {
if ($complexBuilding->getRent() !== null && ($lowestRent === null || $complexBuilding->getRent() < $lowestRent)) {
$lowestRent = $complexBuilding->getRent();
}
}
$earlyLocation = null;
foreach ($buildingsInComplex as $complexBuilding) {
if ($complexBuilding->getDateStartAt() !== null && ($earlyLocation === null || $complexBuilding->getDateStartAt() < $earlyLocation)) {
$earlyLocation = $complexBuilding->getDateStartAt();
}
}
$housingCertificate = $currentUser ? $this->housingCertificateRepository->findOneBy(['user' => $currentUser]) : null;
// Define currentBuildingId
$currentBuildingId = $building->getId();
return $this->render('building/index.html.twig', [
'building' => $building,
'canRequestVisio' => $canRequestVisio,
'liked' => $liked,
'allow' => $allowEdit,
'documents' => $documents,
'certificate' => $housingCertificate,
'buildingsInComplex' => $buildingsInComplex,
'lowestRent' => $lowestRent,
'earlyLocation' => $earlyLocation,
'similarProperties' => $similarProperties,
'user' => $currentUser,
'lastViewedBuildings' => $lastViewedBuildings ?? [],
'currentBuildingId' => $currentBuildingId, // Pass currentBuildingId to the template
]);
}
#[Route(path: ["fr" => "/residence/{id}", "en" => "/en/residence/{id}"], name: 'detail_residence')]
public function indexResidence(Residence $residence)
{
$currentUser = $this->getUser();
return $this->render('residence/index.html.twig', [
'residence' => $residence,
'user' => $currentUser,
]);
}
#[Route(path: ["fr" => "/building/{id}/wantedVisio", "en" => "/en/building/{id}/wantedVisio"], name: 'wanted_visio_building')]
public function createWantedVisio(Building $building, Request $request, Mails $mails, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator)
{
if (!$this->getUser()) {
return $this->redirectToRoute('app_login_site');
}
$email = $mails->createEmail('mails/building/visio.html.twig', ["user" => $this->getUser(), "url" => $urlGenerator->generate('detail_building', ['id' => $building->getId()], UrlGeneratorInterface::ABSOLUTE_URL)])
->to($building->getPropertyManager()->getEmail())
->subject('Demande de visite en visio');
$mails->send($email);
$wantedVisio = new WantedVisio();
$wantedVisio->setRequester($this->getUser())
->setBuilding($building)
->setCreatedAt(new \DateTimeImmutable('now', new \DateTimeZone('Europe/Paris')));
$this->entityManager->persist($wantedVisio);
$this->entityManager->flush();
$this->addFlash('notice', $translator->trans('notice.notilbailleur'));
$currentUser = $this->getUser();
return $this->redirectToRoute('detail_building', ['id' => $building->getId()]);
}
#[Route(path: ["fr" => "/building/add/bailleur", "en" => "/en/building/add/bailleur"], name: 'add_building_bailleur')]
public function addBuilding(Request $request, SessionInterface $session, CityRepository $cityRepository, TranslatorInterface $translator): \Symfony\Component\HttpFoundation\Response
{
if (!$this->authService->checkUserIsConnected($this->getUser())) {
return $this->redirectToRoute('app_login_site');
}
if (!in_array(User::LESSOR, $this->getUser()->getRoles()) && !in_array(User::ADMIN, $this->getUser()->getRoles()) && !in_array(User::RESIDENT, $this->getUser()->getRoles())) {
throw $this->createNotFoundException('not good roles');
}
$building = new Building();
$cities = [];
$citiesForm = [];
$citiesData = $cityRepository->findAll();
foreach ($citiesData as $city) {
$cities[] = $city->getCityName();
$citiesForm[] = $city->getCity() . "," . $city->getPostalCode();
}
$form = $this->createForm(BuildingAddFormType::class, $building, ['cities' => $citiesForm]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$cityEntity = $form->get('cityEntity')->getData();
if (is_null($form->get('minIncome')->getData())) {
$rent = $form->get('rent')->getData();
$building->setMinIncome($rent * 3 * 100);
}
$arrayCity = explode(',', $cityEntity);
$city = $arrayCity[0];
$streetNumber = $form->get('streetNumber')->getData();
$street = $form->get('street')->getData();
if (count($arrayCity) <= 1) {
$postalCode = "";
$dataGoogleMap = $this->googleMapsService->geocodeAddress(
$streetNumber . " " . $street . ", " . $city
);
$cityEntity = $cityRepository->findOneBy(['name' => $city]);
if ($cityEntity) {
$building->setCityEntity($cityEntity);
}
foreach ($dataGoogleMap['0']['address_components'] as $component) {
if (in_array("postal_code", $component['types'])) {
$postalCode = $component['long_name'];
}
}
} else {
$postalCode = $arrayCity[1];
}
$building->setPostalCode($postalCode);
$city = $cityRepository->findOneBy(['city' => $city, 'postalCode' => $postalCode]);
$building->setCityEntity($city);
$building->setIsActive(true);
$building->setIsBlocked(false);
$building->setIsEnd(true);
$uniqueId = $this->generateUniqueFileName();
$building->setUniqueId($uniqueId);
$building->setPropertyManager($this->getUser());
$building->setRent($building->getRent() * 100);
$building->setSecurityDeposit($building->getSecurityDeposit() * 100);
$building->setExpenses($building->getExpenses() * 100);
$this->entityManager->persist($building);
$this->entityManager->flush();
$persistedBuilding = $this->buildingRepository->findOneBy(['uniqueId' => $building->getUniqueId()]);
$persistedBuilding->setNumberId(sprintf('N°%s%s%s%s', $persistedBuilding->getCreatedAt()->format('Y'), $persistedBuilding->getCreatedAt()->format('m'), $persistedBuilding->getCreatedAt()->format('d'), str_pad($persistedBuilding->getId(), 8, '0', STR_PAD_LEFT)));
$this->saveFileWithForm($form, $building);
$this->saveEquipment($form->get('interior')->getData(), $building);
if ($form->get('exterior')->getData()) {
$this->saveEquipment($form->get('exterior')->getData(), $building);
}
$this->entityManager->persist($building);
$this->entityManager->flush();
$persistedBuilding = $this->buildingRepository->findOneBy(['uniqueId' => $building->getUniqueId()]);
$persistedBuilding->setNumberId(sprintf('N°%s%s%s%s', $persistedBuilding->getCreatedAt()->format('Y'), $persistedBuilding->getCreatedAt()->format('m'), $persistedBuilding->getCreatedAt()->format('d'), str_pad($persistedBuilding->getId(), 8, '0', STR_PAD_LEFT)));
$this->entityManager->persist($building);
$this->entityManager->flush();
$this->addFlash('notice', $translator->trans('notice.ajoutBien'));
$currentUser = $this->getUser();
return $this->redirectToRoute('building_edit', ['id' => $persistedBuilding->getId()]);
} elseif ($form->isSubmitted()) {
return $this->render('building/add.html.twig', [
'form' => $form->createView(),
'cities' => $cities,
'user' => $currentUser,
]);
}
return $this->render('building/add.html.twig', [
'form' => $form->createView(),
'cities' => $cities,
'user' => $currentUser,
]);
}
#[Route(path: ["fr" => "/building/{id}/validation", "en" => "/en/building/{id}/validation"], name: 'detail_building_before_validation')]
public function detailBuildingBeforeValidation(Building $building)
{
if (!$this->authService->checkUserIsConnected($this->getUser())) {
return $this->redirectToRoute('app_login_site');
}
$this->CheckUserPerm($building);
$currentUser = $this->getUser();
return $this->render('building/detail_before_validation.html.twig', [
'building' => $building,
'user' => $currentUser,
]);
}
#[Route(path: ["fr" => "/building/{id}/validate", "en" => "/en/building/{id}/validate"], name: 'validate_building')]
public function validateBuilding(Building $building)
{
if (!$this->authService->checkUserIsConnected($this->getUser())) {
return $this->redirectToRoute('app_login_site');
}
$this->CheckUserPerm($building);
$building->setIsActive(true);
$building->setIsEnd(true);
$this->entityManager->persist($building);
$this->entityManager->flush();
$currentUser = $this->getUser();
return $this->redirectToRoute('detail_building', ['id' => $building->getId()]);
}
#[Route(path: ["fr" => "/building/{id}/edit", "en" => "/en/building/{id}/edit"], name: 'building_edit')]
public function editBuilding(Building $building, Request $request, CityRepository $cityRepository, TranslatorInterface $translator)
{
if (!$this->authService->checkUserIsConnected($this->getUser())) {
return $this->redirectToRoute('app_login_site');
}
$this->CheckUserPerm($building);
$cities = [];
$citiesData = $cityRepository->findAll();
foreach ($citiesData as $city) {
$cities[] = $city->getCityName();
}
$complexPropertyId = $building->getComplexPropertyId();
$building->setRent($building->getRent() / 100);
$building->setSecurityDeposit($building->getSecurityDeposit() / 100);
$building->setExpenses($building->getExpenses() / 100);
$form = $this->createForm(BuildingEditFormType::class, $building);
$equipments = [];
foreach ($building->getBuildingEquipment() as $buildingEquipment) {
$equipments[] = $buildingEquipment->getName();
}
$form->handleRequest($request);
$pictures1 = false;
$pictures2 = false;
$pictures3 = false;
$pictures4 = false;
$pictures5 = false;
$pictures6 = false;
$pictures7 = false;
$pictures8 = false;
foreach ($building->getBuildingDocuments() as $buildingDocument) {
if ($buildingDocument->getName() == "base") {
// Supprimer la photo de base
//$this->entityManager->remove($buildingDocument);
} elseif ($buildingDocument->getName() == "file2") {
$pictures2 = $buildingDocument->getImageFile();
} elseif ($buildingDocument->getName() == "file3") {
$pictures3 = $buildingDocument->getImageFile();
} elseif ($buildingDocument->getName() == "file4") {
$pictures4 = $buildingDocument->getImageFile();
} elseif ($buildingDocument->getName() == "file5") {
$pictures5 = $buildingDocument->getImageFile();
} elseif ($buildingDocument->getName() == "file6") {
$pictures6 = $buildingDocument->getImageFile();
} elseif ($buildingDocument->getName() == "file7") {
$pictures7 = $buildingDocument->getImageFile();
} elseif ($buildingDocument->getName() == "file8") {
$pictures8 = $buildingDocument->getImageFile();
} else {
$pictures1 = $buildingDocument->getImageFile();
}
}
if ($form->isSubmitted() && !$form->isValid()) {
$this->addFlash('error', $translator->trans('notice.error'));
}
if ($form->isSubmitted() && $form->isValid()) {
foreach ($building->getBuildingDocuments() as $buildingDocument) {
if (strpos($buildingDocument->getName(), "imagesComplexe") === 0) {
$buildingDocument->setComplexPropertyId($complexPropertyId);
}
if (strpos($buildingDocument->getName(), "base") === 0) {
$buildingDocument->setComplexPropertyId($complexPropertyId);
}
if (strpos($buildingDocument->getName(), "file") === 0) {
$buildingDocument->setComplexPropertyId($complexPropertyId);
}
}
$this->entityManager->persist($buildingDocument);
$this->entityManager->flush();
$cityEntity = $form->get('city')->getData();
$postalCode = $form->get('postalCode')->getData();
$city = $cityRepository->findOneBy(['city' => $cityEntity, 'postalCode' => $postalCode]);
$building->setCityEntity($city);
$this->removeBuildingEquipment($building);
$this->saveFileWithForm($form, $building);
$this->saveEquipment($form->get('interior')->getData(), $building);
if ($form->get('exterior')->getData()) {
$this->saveEquipment($form->get('exterior')->getData(), $building);
}
$building->setRent($building->getRent() * 100);
$building->setSecurityDeposit($building->getSecurityDeposit() * 100);
$building->setExpenses($building->getExpenses() * 100);
$building->setIsEnd(true);
$this->entityManager->persist($building);
$this->entityManager->flush();
foreach ($building->getBuildingDocuments() as $buildingDocument) {
if (strpos($buildingDocument->getName(), "imagesComplexe") === 0) {
$buildingDocument->setComplexPropertyId($complexPropertyId);
}
if (strpos($buildingDocument->getName(), "base") === 0) {
$buildingDocument->setComplexPropertyId($complexPropertyId);
}
if (strpos($buildingDocument->getName(), "file") === 0) {
$buildingDocument->setComplexPropertyId($complexPropertyId);
}
}
if ($building->getComplexProperty()) {
$buildingDocuments = $building->getBuildingDocuments();
$buildingsInComplex = $this->buildingRepository->findByComplexPropertyId($building->getComplexPropertyId());
foreach ($buildingsInComplex as $complexBuilding) {
$complexBuilding->getBuildingDocuments()->initialize();
foreach ($buildingDocuments as $buildingDocument) {
if (strpos($buildingDocument->getName(), "imagesComplexe") === 0) {
$documentExists = false;
foreach ($complexBuilding->getBuildingDocuments() as $complexBuildingDocument) {
if ($complexBuildingDocument->getName() === $buildingDocument->getName()) {
$complexBuildingDocument->setImageFile($buildingDocument->getImageFile());
$documentExists = true;
break;
}
}
if (!$documentExists) {
$newDocument = new BuildingDocument();
$fileName = pathinfo($buildingDocument->getImageFile(), PATHINFO_BASENAME);
$newDocument->setName($buildingDocument->getName());
$newDocument->setImageFile($fileName);
$newDocument->setBuilding($complexBuilding);
$newDocument->setComplexPropertyId($complexBuilding->getComplexPropertyId());
$this->entityManager->persist($newDocument);
}
}
}
$this->entityManager->persist($complexBuilding);
$this->entityManager->flush();
}
}
$this->entityManager->persist($buildingDocument);
$this->entityManager->flush();
$this->addFlash('notice', $translator->trans('notice.validModif'));
return $this->redirectToRoute('detail_building', ['id' => $building->getId()]);
}
return $this->render('building/edit.html.twig', [
'building' => $building,
'form' => $form->createView(),
'cities' => $cities,
'liked' => false,
'equipments' => $equipments,
'pictures1' => $pictures1,
'pictures2' => $pictures2,
'pictures3' => $pictures3,
'pictures4' => $pictures4,
'pictures5' => $pictures5,
'pictures6' => $pictures6,
'pictures7' => $pictures7,
'pictures8' => $pictures8,
]);
}
public function saveEquipment(array $equipments, Building $building)
{
if (!empty($equipments)) {
foreach ($equipments as $equipment) {
$buildingEquipment = new BuildingEquipment();
$buildingEquipment->setBuilding($building)
->setName($equipment)
->setValue(1)
->setResidence(null);
$building->addBuildingEquipment($buildingEquipment);
$this->entityManager->persist($buildingEquipment);
}
}
}
public function saveFileWithForm($form, $building)
{
$files = $this->formFilesToArray($form);
foreach ($files as $key => $file) {
if ($file) {
foreach ($building->getBuildingDocuments() as $buildingDocument) {
if ($buildingDocument->getName() === $key || ($buildingDocument->getName() == "base" && $key == "file1")) {
// Supprimer l'ancienne photo
$building->removeBuildingDocument($buildingDocument);
$this->entityManager->remove($buildingDocument);
}
}
$this->entityManager->flush();
$fileName = $this->generateUniqueFileName() . '.' . $file->guessExtension();
$file->move(
$this->getParameter('building_directory'),
$fileName
);
$buildingDocument = new BuildingDocument();
if ($key === "houseRules") {
$buildingDocument->setName("houseRules");
} else {
$buildingDocument->setName($key);
}
$buildingDocument->setBuilding($building)
->setImageFile($fileName);
$building->addBuildingDocument($buildingDocument);
$this->entityManager->persist($buildingDocument);
}
}
}
public function formFilesToArray($form): array
{
$files = [];
foreach ($form->all() as $key => $value) {
if ($value->getConfig()->getType()->getBlockPrefix() === 'file') {
$files[$key] = $value->getData();
}
}
return $files;
}
private function generateUniqueFileName(): string
{
return md5(uniqid());
}
private function removeBuildingEquipment(Building $building)
{
foreach ($building->getBuildingEquipment() as $buildingEquipment) {
$this->entityManager->remove($buildingEquipment);
}
$this->entityManager->flush();
}
/**
* @Route("/cities/search", name="cities_search")
*/
public function searchAction(Request $request, CityRepository $cityRepository): JsonResponse
{
$q = $request->query->get('term'); // use "term" for jQuery UI
$limit = $request->query->get('limit');
$cities = $cityRepository
->findByTerm($q, $limit);
$formattedCities = [];
foreach ($cities as $city) {
$formattedCities[] = [
'label' => $city->getCity(),
'postalCode' => $city->getPostalCode(),
'value' => $city->getId()
];
}
return new JsonResponse($formattedCities);
}
private function checkUserExist()
{
if (is_null($this->getUser())) {
return $this->redirectToRoute('app_login_site');
}
}
private function CheckUserPerm($building)
{
$this->checkUserExist();
if (!in_array("ROLE_ADMIN", $this->getUser()->getRoles())) {
if ($building->getPropertyManager() != $this->getUser()) {
throw $this->createNotFoundException('not good user');
}
}
}
public function toggleFavorite(Request $request, $id): JsonResponse
{
$user = $this->getUser();
$building = $this->getDoctrine()->getRepository(Building::class)->find($id);
if (!$user || !$building) {
return new JsonResponse(['message' => 'Erreur'], 400);
}
$isFavorite = $user->getFavorites()->contains($building);
if ($isFavorite) {
$user->removeFavorite($building);
$message = 'building.retirefav';
} else {
$user->addFavorite($building);
$message = 'building.ajoutfav';
}
$this->getDoctrine()->getManager()->flush();
return new JsonResponse([
'message' => $message,
'isFavorite' => !$isFavorite // Renvoie le nouvel état
]);
}
}