This content originally appeared on DEV Community and was authored by Aymeric Ratinaud
Imaginez avoir dans votre projet plusieurs entités avec la relation author
comme par exemple ces deux entités suivantes :
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\CourierFavoriteRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: CourierFavoriteRepository::class)]
#[ApiResource()]
class Book
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $author = null;
#[ORM\Column(length: 255)]
private ?string $title = null;
public function getId(): ?int
{
return $this->id;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): static
{
$this->author = $author;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
}
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\TodoRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: TodoRepository::class)]
#[ApiResource()]
class Todo
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $author = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $content = null;
public function getId(): ?int
{
return $this->id;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): static
{
$this->author = $author;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): static
{
$this->content = $content;
return $this;
}
}
Nous voulons verrouiller les résultats des GET item et collection uniquement sur l’user connecté.
Nous allons créer une interface que nous implémenterons sur nos entités
<?php
namespace App\Entity;
interface CurrentUserIsAuthorInterface
{
public function setAuthor(?User $author): static;
}
Maitenant nous allons faire une DoctrineExtension
qui va ajouter la contrainte where
dans le QueryBuilder
sur l’utilisateur connecté.
<?php
namespace App\DoctrineExtension;
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use App\Entity\CurrentUserIsAuthorInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bundle\SecurityBundle\Security;
class CurrentUserIsAuthorExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
public function __construct(
private Security $security,
) {
}
public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
{
$this->currentUserIsAuthor($resourceClass, $queryBuilder);
}
public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, ?Operation $operation = null, array $context = []): void
{
$this->currentUserIsAuthor($resourceClass, $queryBuilder);
}
/**
* @param string $resourceClass
* @param QueryBuilder $queryBuilder
* @return void
* @throws ReflectionException
*/
public function currentUserIsAuthor(string $resourceClass, QueryBuilder $queryBuilder): void
{
$reflectionClass = new \ReflectionClass($resourceClass);
if ($reflectionClass->implementsInterface(CurrentUserIsAuthorInterface::class)) {
$alias = $queryBuilder->getRootAliases()[0];
$queryBuilder->andWhere("$alias.author = :current_author")
->setParameter('current_author', $this->security->getUser()->getId());
}
}
}
Maintenant il nous reste à implémenter notre interface sur nos entités :
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\CourierFavoriteRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: CourierFavoriteRepository::class)]
#[ApiResource()]
class Book implements CurrentUserIsAuthorInterface
{
// ...
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use App\Repository\TodoRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: TodoRepository::class)]
#[ApiResource()]
class Todo implements CurrentUserIsAuthorInterface
{
// ...
Et c’est tout. Pour chaque GET item ou collection vous aurez uniquement les entrées avec l’utilisateurs qui est connecté
Lisez aussi “comment enregistrer automatiquement l’utilisateur connecté” : https://dev.to/aratinau/automatisons-lenregistrement-du-user-sur-nimporte-quelle-entite-4f68
This content originally appeared on DEV Community and was authored by Aymeric Ratinaud