Imaginez avoir dans votre projet plusieurs entités avec la relation author
comme par exemple ces deux entités suivantes :
namespace AppEntity;
use ApiPlatformMetadataApiResource;
use AppRepositoryCourierFavoriteRepository;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: CourierFavoriteRepository::class)]
#[ApiResource()]
class Book
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMManyToOne]
#[ORMJoinColumn(nullable: false)]
private ?User $author = null;
#[ORMColumn(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;
}
}
namespace AppEntity;
use ApiPlatformMetadataApiResource;
use AppRepositoryTodoRepository;
use DoctrineDBALTypesTypes;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: TodoRepository::class)]
#[ApiResource()]
class Todo
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMManyToOne]
#[ORMJoinColumn(nullable: false)]
private ?User $author = null;
#[ORMColumn(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
namespace AppEntity;
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é.
namespace AppDoctrineExtension;
use ApiPlatformDoctrineOrmExtensionQueryCollectionExtensionInterface;
use ApiPlatformDoctrineOrmExtensionQueryItemExtensionInterface;
use ApiPlatformDoctrineOrmUtilQueryNameGeneratorInterface;
use ApiPlatformMetadataOperation;
use AppEntityCurrentUserIsAuthorInterface;
use DoctrineORMQueryBuilder;
use SymfonyBundleSecurityBundleSecurity;
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 :
namespace AppEntity;
use ApiPlatformMetadataApiResource;
use AppRepositoryCourierFavoriteRepository;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: CourierFavoriteRepository::class)]
#[ApiResource()]
class Book implements CurrentUserIsAuthorInterface
{
// ...
namespace AppEntity;
use ApiPlatformMetadataApiResource;
use AppRepositoryTodoRepository;
use DoctrineDBALTypesTypes;
use DoctrineORMMapping as ORM;
#[ORMEntity(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