Admettons que nous ayons des entités avec l’attribut author, nous allons voir comment factoriser la logique en une ligne pour enregistrer l’utilisateur automatiquement.
Prenons l’exemple de cette entité qui contient l’attribut author.
namespace AppEntity;
use AppRepositoryCategoryRepository;
use DoctrineORMMapping as ORM;
#[ORMEntity(repositoryClass: CategoryRepository::class)]
class Category
{
#[ORMId]
#[ORMGeneratedValue]
#[ORMColumn]
private ?int $id = null;
#[ORMColumn(length: 255)]
private ?string $name = null;
#[ORMManyToOne]
#[ORMJoinColumn(nullable: false)]
private ?User $author = null;
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): static
{
$this->author = $author;
return $this;
}
}
Dans notre projet nous avons également une dizaine d’entités qui contient également l’attribut author.
La premiere solution serait de faire un controller ou un DoctrineListener pour chaque entité. Comme celui-là par exemple :
namespace AppDoctrineListener;
use AppEntityCategory;
use DoctrineBundleDoctrineBundleAttributeAsEntityListener;
use DoctrineORMEvents;
use DoctrinePersistenceEventLifecycleEventArgs;
#[AsEntityListener(event: Events::prePersist, entity: Category::class)]
class CategoryDoctrineListener
{
public function __construct(
private Security $security,
) {
}
public function prePersist(Category $category, LifecycleEventArgs $event)
{
$user = $this->security->getUser();
$entity->setAuthor($user);
}
}
Au lieu de ça nous allons garder la logique métier de CategoryDoctrineListener et l’adapter à toutes les entités qui contiennent l’attribut author
Pour cela nous allons faire une interface
namespace AppEntity;
interface AuthorInterface
{
public function setAuthor(?User $author): static;
}
Ainsi nous allons l’implementer sur toutes les entités qui ont la méthode setAuthor
Exemple avec Catégory
namespace AppEntity;
use ApiPlatformMetadataApiResource;
use AppRepositoryCategoryRepository;
use DoctrineORMMapping as ORM;
use SymfonyComponentSerializerAttributeGroups;
#[ORMEntity(repositoryClass: CategoryRepository::class)]
#[ApiResource(paginationEnabled: false)]
class Category implements AuthorInterface
// …
Maintenant nous pouvons créer un DoctrineListener qui regarde si l’entité implemente AuthorInterface en utilisant la réflexion comme suit
namespace AppDoctrineListener;
use AppEntityAuthorInterface;
use DoctrineBundleDoctrineBundleAttributeAsDoctrineListener;
use DoctrineORMEventPrePersistEventArgs;
use SymfonyBundleSecurityBundleSecurity;
#[AsDoctrineListener(‘prePersist’)]
class AttachAuthorDoctrineListener
{
public function __construct(
private Security $security,
) {
}
public function prePersist(PrePersistEventArgs $event): void
{
$entity = $event->getObject();
$reflectionClass = new ReflectionClass($entity);
if (!$reflectionClass->implementsInterface(AuthorInterface::class)) {
return;
}
$user = $this->security->getUser();
$entity->setAuthor($user);
}
}
Et c’est tout, maintenant vous n’aurez qu’à ajouter implements AuthorInterface sur les entités qui ont besoin d’enregistrer l’auteur 🚀