This commit is contained in:
Tykayn 2025-02-14 15:35:03 +01:00 committed by tykayn
parent d8c1b7c0f6
commit d01ecdabba
13 changed files with 198 additions and 25 deletions

View file

@ -0,0 +1,18 @@
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class LoginController extends AbstractController
{
#[Route('/login', name: 'app_login')]
public function index(): Response
{
return $this->render('login/index.html.twig', [
'controller_name' => 'LoginController',
]);
}
}

View file

@ -25,8 +25,9 @@ class SecurityController extends AbstractController
}
#[Route(path: '/logout', name: 'app_logout')]
public function logout(): void
public function logout(): Response
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
return $this->redirectToRoute('app_default');
}
}

View file

@ -3,12 +3,17 @@
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\ApiProperty;
use App\Repository\ProductRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Filter\UserProductsFilter;
use App\DTO\UserDTO;
#[ApiResource(paginationEnabled: false)]
#[UserProductsFilter]
#[ORM\Entity(repositoryClass: ProductRepository::class)]
class Product
{
@ -30,12 +35,14 @@ class Product
* @var Collection<int, GroupOfProducts>
*/
#[ORM\ManyToMany(targetEntity: GroupOfProducts::class, mappedBy: 'products')]
#[ApiProperty(readable: false)]
private Collection $groupOfProducts;
/**
* @var Collection<int, Selling>
*/
#[ORM\ManyToMany(targetEntity: Selling::class, mappedBy: 'products')]
#[ApiProperty(readable: false)]
private Collection $sellings;
#[ORM\ManyToOne(inversedBy: 'products')]

View file

@ -0,0 +1,27 @@
<?php
namespace App\EventSubscriber;
use ApiPlatform\Symfony\EventListener\EventPriorities;
use ApiPlatform\EventListener\FilterCollectionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
final class NotShownCountSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
FilterCollectionEvent::class => ['addNotShownCount', EventPriorities::PRE_WRITE],
];
}
public function addNotShownCount(FilterCollectionEvent $event): void
{
$context = $event->getContext();
if (isset($context['notShownCount'])) {
$event->getResponse()->setData(array_merge($event->getResponse()->getData(), [
'notShownCount' => $context['notShownCount'],
]));
}
}
}

View file

@ -0,0 +1,52 @@
<?php
/**
* filtrer les objets selon ceux qui appartiennent uniquement à l'utilisateur connecté
*/
namespace App\Filter;
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use Doctrine\ORM\QueryBuilder;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\FilterInterface;
final class UserProductsFilter extends AbstractFilter implements FilterInterface
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
{
if ($property === 'user' && $this->security->isGranted('ROLE_USER')) {
$user = $this->security->getUser();
$queryBuilder->andWhere('o.user = :user')->setParameter('user', $user);
// Compter le nombre total de produits pour l'utilisateur
$totalProducts = $queryBuilder->getEntityManager()->getRepository('App\Entity\Product')->count(['user' => $user]);
$filteredProducts = $queryBuilder->getQuery()->getResult();
$notShownCount = $totalProducts - count($filteredProducts);
// Ajouter le nombre de produits non montrés au contexte
$context['notShownCount'] = $notShownCount;
}
}
public function getDescription(string $resourceClass): array
{
return [
'user' => [
'property' => 'user',
'type' => 'string',
'required' => false,
'swagger' => [
'description' => 'Filtrer les produits par utilisateur connecté',
],
],
];
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Security;
use App\Repository\AccessTokenRepository;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class AccessTokenHandler implements AccessTokenHandlerInterface
{
public function __construct(
private AccessTokenRepository $repository
) {
}
public function getUserBadgeFrom(string $accessToken): UserBadge
{
// e.g. query the "access token" database to search for this token
$accessToken = $this->repository->findOneByValue($accessToken);
if (null === $accessToken || !$accessToken->isValid()) {
throw new BadCredentialsException('Invalid credentials.');
}
// and return a UserBadge object containing the user identifier from the found token
// (this is the same identifier used in Security configuration; it can be an email,
// a UUID, a username, a database ID, etc.)
return new UserBadge($accessToken->getUserId());
}
}