<?php
declare(strict_types=1);
/**
* @author Mehrez Labidi
*/
namespace App\Security\Voter;
use App\Entity\Model\Annonces;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\HttpFoundation\RequestStack;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\{
AnnoncesAcheteur,
AnnoncesVendeur,
DetailsCommande,
Commandes
};
/**
* Voter de sécurité pour l'accès aux annonces commandées par l'utilisateur.
*
* Vérifie que l'utilisateur connecté a bien passé une commande liée à l'annonce
* (acheteur ou vendeur) et que cette commande est dans un état valide
* (information transmise ou facture envoyée) avant d'autoriser l'accès.
*/
class AnnonceCommandVoter extends Voter {
public const ANNONCE_COMMANDE = 'ANNONCE_COMMANDE';
private $requestStack;
private $em;
public function __construct(RequestStack $requestStack, EntityManagerInterface $em) {
$this->requestStack = $requestStack;
$this->em = $em;
}
protected function supports(string $attribute, $subject): bool {
$subject = $this->transformArrayToFakeObjAnnonce($subject);
return $attribute === self::ANNONCE_COMMANDE && $subject instanceof Annonces;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool {
$request = $this->requestStack->getCurrentRequest();
if (!$request || !$subject) {
return false;
}
$user = $token->getUser();
if (!$user) {
return false;
}
$subject = $this->transformArrayToFakeObjAnnonce($subject);
$idAnnonce = $subject->getId();
$typeRapprochement = $subject->getTypeRaprochement();
if (in_array($typeRapprochement, Annonces::$TYPE_RAPROCHEMENT_VENDEUR)) {
$qb = $this->em->createQueryBuilder();
$result = $qb->select('c.etat')
->from(AnnoncesVendeur::class, 'av')
->leftJoin(DetailsCommande::class, 'dc', 'WITH', 'av.id_annonce_vendeur = dc.id_annonce AND dc.type_annonce = :type_annonce')
->leftJoin(Commandes::class, 'c', 'WITH', 'c.id_commande = dc.id_commande')
->where('dc.id_cpte_utilisateur = :user')->setParameter('user', $user->getLogin())
->andWhere('av.id_annonce_vendeur = :idAnnonce')->setParameter('idAnnonce', $idAnnonce)
->setParameter('type_annonce', 'vendeur')
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
return $result !== null && !empty($result['etat']) && (in_array($result['etat'], ['information_transmise', 'facture_envoyee', 'cmde_valide']));
}
if (in_array($typeRapprochement, Annonces::$TYPE_RAPROCHEMENT_ACHETEUR)) {
$qb = $this->em->createQueryBuilder();
$result = $qb->select('c.etat')
->from(AnnoncesAcheteur::class, 'aa')
->leftJoin(DetailsCommande::class, 'dc', 'WITH', 'aa.id_annonce_acheteur = dc.id_annonce AND dc.type_annonce = :type_annonce')
->leftJoin(Commandes::class, 'c', 'WITH', 'c.id_commande = dc.id_commande')
->where('dc.id_cpte_utilisateur = :user')
->andWhere('aa.id_annonce_acheteur = :idAnnonce')->setParameter('idAnnonce', $idAnnonce)
->setParameter('type_annonce', 'acheteur')->setParameter('user', $user->getLogin())
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
return $result !== null && !empty($result['etat']) && (in_array($result['etat'], ['information_transmise', 'facture_envoyee', 'cmde_valide']));
}
return false;
}
/**
* Transforme un tableau associatif en objet factice d'annonce (AnnoncesVendeur ou AnnoncesAcheteur).
*
* @param array|mixed $subject Tableau contenant les données de l'annonce ou objet déjà existant.
* @return AnnoncesVendeur|AnnoncesAcheteur|mixed L'objet factice créé ou le sujet original si non transformable.
*/
private function transformArrayToFakeObjAnnonce($subject) {
if (is_array($subject) && !empty($subject)) {
if (!empty($subject['type_annonce']) && $subject['type_annonce'] == 'vendeur') {
$fakeObj = new AnnoncesVendeur();
$fakeObj->_set("id_annonce_vendeur", $subject['id_annonce']);
$fakeObj->_set("type_raprochement", "cession");
}
if (!empty($subject['type_annonce']) && $subject['type_annonce'] == 'acheteur') {
$fakeObj = new AnnoncesAcheteur();
$fakeObj->_set("id_annonce_acheteur", $subject['id_annonce']);
$fakeObj->_set("type_raprochement", "acquisition");
}
return $fakeObj;
} else {
return $subject;
}
}
}