<?php
namespace App\Twig;
use App\Entity\Company;
use App\Entity\Event;
use App\Entity\ExternalCompany;
use App\Entity\MarketplaceReservation;
use App\Entity\Registration;
use App\Entity\Specialist;
use App\Entity\SpecialistEventApplication;
use App\Entity\User;
use App\Entity\VisioEvent;
use App\Entity\Workshop;
use App\Service\PriceService;
use App\Service\ToolsService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use Symfony\Component\Asset\Packages;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Twig\TwigTest;
use Vich\UploaderBundle\Storage\StorageInterface;
use function Composer\Autoload\includeFile;
class AppFunctions extends AbstractExtension
{
/**
* @var Security
*/
private $security;
/**
* @var EntityManagerInterface
*/
private $em;
/**
* @var StorageInterface
*/
private $storage;
/**
* @var Packages
*/
private $packages;
/**
* @var UrlGeneratorInterFace
*/
private $urlGeneratorInterface;
/**
* @var PriceService
*/
private $priceService;
public function __construct(Security $security, EntityManagerInterface $em, StorageInterface $storage,
Packages $packages, PriceService $priceService, TranslatorInterface $translator,
UrlGeneratorInterface $urlGeneratorInterface) {
$this->security = $security;
$this->em = $em;
$this->storage = $storage;
$this->packages = $packages;
$this->priceService = $priceService;
$this->translator = $translator;
$this->urlGeneratorInterface = $urlGeneratorInterface;
}
/**
* @return TwigTest[]
*/
public function getTests(): array
{
return [
new TwigTest('image', [$this, 'isImage']),
new TwigTest('application_available', [$this, 'isEventApplicable']),
];
}
/**
* Checks if the specialist can postulate to the event
* @param Event $event
* @return bool
*/
public function isEventApplicable(Event $event): bool
{
$result = false;
if ($this->security->getUser() != null && !$this->security->isGranted(User::ROLE_SPECIALIST)){
throw new LogicException('You are trying to use this filter with a non connected environnement or a wrong user');
}
if ($event->getStatus() == Event::STATUS_OPEN && $event->getStart() > new \DateTime()) {
$users = $event->getApplications()->map(function ($element) {
return $element->getSpecialist()->getUser()->getId();
});
if (!$users->contains($this->security->getUser()->getId())) {
$result = true;
}
}
return $result;
}
/**
* @param string $filename
* @return bool
*/
public function isImage(string $filename): bool
{
$supported_image = array(
'gif',
'jpg',
'jpeg',
'png'
);
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); // Using strtolower to overcome case sensitive
if (in_array($ext, $supported_image)) {
return true;
}
return false;
}
/**
* @return TwigFunction[]
*/
public function getFunctions(): array
{
return [
new TwigFunction('clientCompany', [$this, 'getClientCompany']),
new TwigFunction('userCompany', [$this, 'getUserCompany']),
new TwigFunction('companyLogo', [$this, 'getCompanyLogo']),
new TwigFunction('applicationPrice', [$this, 'getApplicationPrice']),
new TwigFunction('badgeColor', [$this, 'getBadgeColor']),
new TwigFunction('displayDate', [$this, 'displayDate']),
new TwigFunction('generateDeleteModal', [$this, 'generateDeleteModal']),
new TwigFunction('displayEventStatus', [$this, 'displayEventStatus']),
new TwigFunction('displayAccessTitle', [$this, 'displayAccessTitle']),
new TwigFunction('estimatedSpecialistPrice', [$this, 'getEstimatedSpecialistPrice']),
new TwigFunction('generateCancelModal', [$this, 'generateCancelModal']),
new TwigFunction('generateEventCreationModal', [$this, 'generateEventCreationModal']),
new TwigFunction('visioCanceledPercent', [$this, 'visioCancelledPercentSpecialist']),
new TwigFunction('displaySpecialistStatus', [$this, 'displaySpecialistStatus']),
new TwigFunction('generateEventUrl', [$this, 'generateEventUrl']),
new TwigFunction('displayWorkshopType', [$this, 'displayWorkshopType']),
new TwigFunction('displayPaymentStatus', [$this, 'displayPaymentStatus']),
new TwigFunction('displayReservationStatus', [$this, 'displayReservationStatus']),
new TwigFunction('displayRegistrationStatus', [$this, 'displayRegistrationStatus']),
new TwigFunction('tradStatusVisio', [$this, 'tradStatusVisio']),
];
}
/**
* @param SpecialistEventApplication $application
* @param Company $company
* @return float
*/
public function getApplicationPrice(SpecialistEventApplication $application, Company $company): float
{
return $this->priceService->calculatePriceEvent($company, $application);
}
/**
* @param Event $event
* @param Specialist $specialist
* @return float
*/
public function getEstimatedSpecialistPrice(Event $event, Specialist $specialist): float
{
return $this->priceService->calculateEstimatedSpecialistEventPrice($event, $specialist);
}
/**
* @return Company|mixed|object|null
*/
public function getClientCompany()
{
try {
$company = $this->security->getUser()->getClient()->getCompany();
} catch (\Throwable $th) {
return null;
}
return $this->em->getRepository(Company::class)->findOneBy(['id' => $company->getId()]);
}
/**
* @return Company|null
*/
public function getUserCompany(): ?Company
{
try {
$user = $this->security->getUser();
} catch (\Throwable $th) {
throw new LogicException("User not connected");
}
$company = $this->em->getRepository(Company::class)->findOneBy(['user' => $user->getId()]);
if (!$company instanceof Company){
throw new LogicException("Calling a company on a non company user");
}
return $company;
}
/**
* Returns company logo url depending on if it's external or not
*
* @param Company|null $company
* @return string|null
*/
public function getCompanyLogo(Company $company = null): ?string
{
try {
$company = $company ?? $this->getUserCompany();
return $this->storage->resolveUri($company, 'imageFile', Company::class);
}catch (\Exception $e){
return $this->packages->getUrl('build/images/toreplace.jpg');
}
}
public function getBadgeColor($value, array $configs = null): ?string
{
$color = "success";
$configs = [
'colors' => ["danger", "warning", "success"],
'steps' => [
["min" => 0, "max" => 25],
["min" => 25, "max" => 50],
["min" => 50, "max" => 100],
],
];
foreach($configs['steps'] as $key => $stepConfig) {
if($value >= $stepConfig['min'] && $value < $stepConfig['max'])
$color = $configs['colors'][$key];
}
return $color;
}
public function displayDate($value, $return = 'full')
{
if ($value instanceof DateTime) {
if($return == 'date') {
return $value->format('d/m/Y');
}else if($return == 'date-text') {
return $value->format('d')." ".ToolsService::getFrenchMonths($value->format('m'));
}else if($return == 'date-text-year') {
return $value->format('d')." ".ToolsService::getFrenchMonths($value->format('m'))." ".$value->format('Y');
}else if($return == 'time') {
return $value->format('H') ."H". $value->format('i');
}else if($return == 'no-seconds'){
return $value->format('d/m/Y H')."H". $value->format('i');
}else if($return == 'text'){
return $value->format('d')." ".ToolsService::getFrenchMonths($value->format('m'))." à ". $value->format('H') ."H". $value->format('i');
} else if($return == 'full-text') {
return $value->format('d')." ".ToolsService::getFrenchMonths($value->format('m'))." ".$value->format('Y')." à ". $value->format('H') ."H". $value->format('i');
}
return $value->format('d/m/Y H:i:s');
}else{
return "";
}
}
public function generateDeleteModal($myModalDatas)
{
$default = array(
'buttonText' => $this->translator->trans('delete', [], 'commun'),
'buttonClass' => "btn btn-danger btn-sm me-1",
'modalTitle' => $this->translator->trans('modal.delete.title', [], 'commun'),
'modalCloseText' => $this->translator->trans('close', [], 'commun'),
'modalAcceptText' => $this->translator->trans('accept', [], 'commun'),
'modalDeactivateText' => $this->translator->trans('deactivate', [], 'commun'),
'modalActivateText' => $this->translator->trans('activate', [], 'commun'),
);
$deactivateCTA = '';
if (!empty($myModalDatas['deactivateUrl'])) {
if ($myModalDatas['deactivate'] == true) {
$deactivateCTA = '<a href="' . $myModalDatas['deactivateUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $default['modalDeactivateText'] . '</a>';
}else{
$deactivateCTA = '<a href="' . $myModalDatas['deactivateUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $default['modalActivateText'] . '</a>';
}
}
$myModalDatas = array_merge($default, $myModalDatas);
return '<button type="button" class="'.$myModalDatas['buttonClass'].'" data-bs-toggle="modal" data-bs-target="#delete' . $myModalDatas['id'] . '">
<i data-feather="trash"></i>
</button>
<div class="modal fade text-start modal-warning" id="delete' . $myModalDatas['id'] . '" tabindex="-1" aria-labelledby="deleteModalLabel' . $myModalDatas['id'] . '" style="display: none;" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel' . $myModalDatas['id'] . '">' . $myModalDatas['modalTitle'] . '</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
' . $this->translator->trans('modal.delete.text10', [], 'commun') . '<br>
<b>' . $myModalDatas['label'] . '</b>.<br>
' . $this->translator->trans('modal.delete.text20', [], 'commun') . '<br>
' . $this->translator->trans('modal.delete.text40', [], 'commun') . '
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark waves-effect waves-float waves-light" data-bs-dismiss="modal">' . $myModalDatas['modalCloseText'] . '</button>
' .$deactivateCTA. '
<a href="' . $myModalDatas['deleteUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $myModalDatas['modalAcceptText'] . '</a>
</div>
</div>
</div>
</div>';
}
public function generateEventCreationModal($myModalDatas)
{
$default = array(
'buttonText' => $this->translator->trans('delete', [], 'commun'),
'buttonClass' => "btn btn-success btn-sm me-1",
'modalTitle' => $this->translator->trans('modal.delete.title', [], 'commun'),
'modalCloseText' => $this->translator->trans('close', [], 'commun'),
'modalCreateEventText' => $this->translator->trans('modal.create_event.create_text', [], 'commun'),
'modalCreateRoomText' => $this->translator->trans('modal.create_event.create_room', [], 'commun'),
'modalDeactivateText' => $this->translator->trans('deactivate', [], 'commun'),
'modalActivateText' => $this->translator->trans('activate', [], 'commun'),
);
$deactivateCTA = '';
if (!empty($myModalDatas['deactivateUrl'])) {
if ($myModalDatas['deactivate'] == true) {
$deactivateCTA = '<a href="' . $myModalDatas['deactivateUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $default['modalDeactivateText'] . '</a>';
}else{
$deactivateCTA = '<a href="' . $myModalDatas['deactivateUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $default['modalActivateText'] . '</a>';
}
}
$myModalDatas = array_merge($default, $myModalDatas);
return '<button type="button" class="'.$myModalDatas['buttonClass'].'" data-bs-toggle="modal" data-bs-target="#delete' . $myModalDatas['id'] . '">
<i data-feather="plus-square"></i>
</button>
<div class="modal fade text-start modal-warning" id="delete' . $myModalDatas['id'] . '" tabindex="-1" aria-labelledby="deleteModalLabel' . $myModalDatas['id'] . '" style="display: none;" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel' . $myModalDatas['id'] . '">' . $myModalDatas['modalTitle'] . '</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-wrap">
' . $this->translator->trans('modal.create_event.text10', [], 'commun') . '<br>
<b>' . $myModalDatas['companyName'] . '</b>.<br>
' . $this->translator->trans('modal.create_event.text20', [], 'commun') . '<br>
' . $this->translator->trans('modal.create_event.text40', [], 'commun') . '
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark waves-effect waves-float waves-light" data-bs-dismiss="modal">' . $myModalDatas['modalCloseText'] . '</button>
' .$deactivateCTA. '
<a href="' . $myModalDatas['createRoomUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $myModalDatas['modalCreateRoomText'] . '</a>
</div>
</div>
</div>
</div>';
}
public function generateCancelModal($myModalDatas)
{
$default = array(
'buttonText' => $this->translator->trans('cancel', [], 'commun'),
'modalTitle' => $this->translator->trans('modal.cancel.title', [], 'commun'),
'modalCloseText' => $this->translator->trans('close', [], 'commun'),
'modalAcceptText' => $this->translator->trans('accept', [], 'commun'),
'modalDeactivateText' => $this->translator->trans('deactivate', [], 'commun'),
'modalActivateText' => $this->translator->trans('activate', [], 'commun'),
'buttonClass' => "btn btn-warning btn-sm me-1",
'redirectRoute' => "admin_event_index",
'buttonContent' => "<i data-feather='x-circle'></i>",
'buttonDisabled' => false,
);
$deactivateCTA = '';
if (!empty($myModalDatas['deactivateUrl'])) {
if ($myModalDatas['deactivate'] == true) {
$deactivateCTA = '<a href="' . $myModalDatas['deactivateUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $default['modalDeactivateText'] . '</a>';
}else{
$deactivateCTA = '<a href="' . $myModalDatas['deactivateUrl'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $default['modalActivateText'] . '</a>';
}
}
$myModalDatas = array_merge($default, $myModalDatas);
if ($myModalDatas['buttonDisabled'] == true) $myModalDatas['buttonClass'] .= " disabled";
$text20 = (isset($myModalDatas['isFree']) && $myModalDatas['isFree'] == false) ? $this->translator->trans('modal.cancel.text20', [], 'commun') : '';
return '<button type="button" class="'.$myModalDatas['buttonClass'].'" data-bs-toggle="modal" data-bs-target="#cancel' . $myModalDatas['id'] . '">'
.$myModalDatas['buttonContent'].
'</button>
<div class="modal fade text-start modal-warning" id="cancel' . $myModalDatas['id'] . '" tabindex="-1" aria-labelledby="cancelModalLabel' . $myModalDatas['id'] . '" style="display: none;" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="cancelModalLabel' . $myModalDatas['id'] . '">' . $myModalDatas['modalTitle'] . '</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
' . $this->translator->trans('modal.cancel.text10', [], 'commun') . '<br>
<b>' . $myModalDatas['label'] . '</b>.<br>
' . $text20 . '<br>
' . $this->translator->trans('modal.cancel.text40', [], 'commun') . '
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark waves-effect waves-float waves-light" data-bs-dismiss="modal">' . $myModalDatas['modalCloseText'] . '</button>
' .$deactivateCTA. '
<a href="' . $myModalDatas['cancelUrl'] . '?redirect_route=' . $myModalDatas['redirectRoute'] . '" class="btn btn-warning waves-effect waves-float waves-light">' . $myModalDatas['modalAcceptText'] . '</a>
</div>
</div>
</div>
</div>';
}
public function displayEventStatus($eventStatus)
{
if ($eventStatus != null) {
if ($eventStatus == "open") {
return "En attente d'expert";
} else if ($eventStatus == "canceled") {
return "Annulé";
} else if ($eventStatus == "finished") {
return "Terminé";
} else if ($eventStatus == "valid") {
return "A venir";
}
}
return "-";
}
/**
* @param Specialist $specialist
* @return array
*/
public function visioCancelledPercentSpecialist(Specialist $specialist): array
{
return $this->em->getRepository(VisioEvent::class)->getCancelRatioSpecialist($specialist);
}
public function displayAccessTitle( string $envSlug)
{
if ($envSlug != null) {
if ($envSlug == "admin") {
return "Accès <br> Admin";
}else if ($envSlug == "expert") {
return "Accès <br> Expert";
}else if ($envSlug == "company") {
return "Accès <br> Entreprise";
}else if ($envSlug == "client") {
return "Plateforme de réservation <br> de vos cours et ateliers";
}
}else{
return "Plateforme de réservation <br> de vos cours et ateliers";
}
}
public function displaySpecialistStatus($specialistStatus)
{
if ($specialistStatus != null) {
if ($specialistStatus == "granted") {
return "Accepté";
}else if ($specialistStatus == "refused") {
return "Refusé";
}else if ($specialistStatus == "waiting_ulteam_confirmation") {
return "En attente de validation";
}else if ($specialistStatus == "waiting_mail_confirmation") {
return "Doit valider son mail";
}
}else{
return "-";
}
}
public function generateEventUrl($eventId)
{
return $this->urlGeneratorInterface->generate('admin_event_edit', ['id' => $eventId], UrlGeneratorInterface::ABSOLUTE_URL);;
}
public function displayWorkshopType(Workshop $workshop)
{
if ($workshop instanceof Workshop) {
if ($workshop->getIsVirtual() == true) {
return "Atelier virtuel";
} else if ($workshop->getIsVirtual() == false) {
return "Atelier collectif";
}
}
return "-";
}
/**
* Pour le payment status des MarketplaceReservation
* @param String $paymentStatus
* @return String
*/
public function displayPaymentStatus(string $paymentStatus)
{
return ToolsService::displayPaymentStatus($paymentStatus);
}
/**
* Pour le status des MarketplaceReservation
* @param String $reservationStatus
* @return String
*/
public function displayReservationStatus(string $reservationStatus)
{
return ToolsService::displayReservationStatus($reservationStatus);
}
/**
* Pour le status des Registration
* @param String $registrationStatus
* @return String
*/
public function displayRegistrationStatus(String $registrationStatus)
{
return ToolsService::displayRegistrationStatus($registrationStatus);
}
/**
* Permet de traduire les status des visio dans les Statistiques
* @param String $status
* @return String
*/
public function tradStatusVisio(string $status): String
{
return ToolsService::tradStatusVisio($status);
}
}