在Doctrine中使用实体时,添加某些"帮助"非常明显。实体的方法。举个例子;
class Post {
protected $tags;
public function __construct() {
$this->tags = new ArrayCollection();
}
public function getTags() {
return $this->tags;
}
public function addTag( $tagName ) {
$tag = new Tag();
$tag->setName( $tagName );
$this->getTags()->add( $tag );
}
}
这本身就有效,它可以提供干净的代码:
$post = new Post();
$post->addTag('Economy');
但是,如果Tag
是多对多关系,并且在向帖子添加标记时我们想检查标记是否已存在,则会出现问题。例如。一个帖子可能没有标签' Economy'因此,从帖子的角度来看,将其添加到帖子中将是一个新标签。但是,如果标签经济'已存在于数据库中我们遇到了问题。我们希望我们的实体尽可能成为POPO,即不要引用实体经理或存储库。
解决这个问题的好策略是什么?
答案 0 :(得分:0)
您需要在实体外部执行此操作。例如......
class Post {
// ...
public function addTag(Tag $tag) {
$this->getTags()->add($tag);
}
}
并且说,控制器...
$post = new Post();
// I can't remember if this returns null for no records found or throws
// an exception. Needs checking
$tag = $em->getRepository('Tag')->findOneByName('Economy');
if ($tag == null) {
$tag = new Tag();
$tag->setName('Economy');
$em->persist($tag); // don't need to do this if you use cascade persist
}
$post->addTag($tag);
答案 1 :(得分:0)
我只是和别人谈论这件事。通过使用生命周期事件,这个问题实际上可以非常优雅地解决。
如果在Post实体上实现了预先持久的生命周期事件,则可以从生命周期事件对象访问实体管理器。从实体管理器可以请求存储库,并且可以调用检查重复项的添加标记的方法。
/**
* @ORM\Entity(repositoryClass="PostRepository")
* @ORM\HasLifecycleCallbacks()
*/
class Post {
public function onPrePersist( LifecycleEventArgs $event ) {
$entityManager = $event->getEntityManager();
$repository = $entityManager->getRepository( get_class( $this ) );
$repository->syncTags( $this );
}
}
同时,在PostRepository
:
class PostRepository {
public function syncTags( Post $post ) {
$em = $this->getEntityManager();
$tagsRepository = $em->getRepository('Tag');
$tags = $post->getTags();
foreach( $tags as $tag ) {
$tagId = $tag->getId();
if( empty( $tagId ) ) {
$existingTag = $tagsRepository->findOneByName( $tag->getName() );
if( ! empty( $existingTag ) ) {
$tags->removeElement( $tag );
$tags->add( $existingTag );
}
}
}
}
}
上面的syncTags
方法基本上遍历Post标签。如果标签没有Id,我们可以假设它以前从未被保留过,因此被添加为新标签。然后我们检查是否已经有一个带有该名称的标签。如果没有,我们可以将其保留为新标记,否则我们会删除副本并添加现有标记实体。
我们现在可以保持标签添加逻辑尽可能简单:
$post = new Post();
$post->addTag('Economy');
如果'经济'标签已经存在,则会使用它,否则将创建新标签。