我不确定我想做的事情是否可行,但我无法找到任何文件。希望我只是在错误的地方寻找。
我想要做的是加载一个始终加载相关对象子集的对象。一些背景 - 我想保留用户删除的联系人的历史记录,因此当删除联系人时,我将db中的isDeleted
列设置为true。我很少想加载已删除的联系人,所以我稍后会担心。但是,当我加载用户,然后加载联系人(在我的情况下通过序列化整个user
对象),所有联系人都被加载,包括已删除的联系人。所以我想只加载尚未删除的联系人。这就是我现在所拥有的,而且我不知道为什么它不起作用。
use Doctrine\Common\Collections\Criteria,
Doctrine\Common\Collections\ArrayCollection;
class User{
/**
* @ORM\OneToMany(targetEntity="Contacts", mappedBy="user", cascade={"persist"}, fetch="EXTRA_LAZY")
* @ORM\JoinColumn(name="contact_id", referencedColumnName="contact_id")
*/
private $contacts;
public function __construct(){
$this->contacts = new ArrayCollection();
}
/**
* Get contacts
*
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getContacts()
{
// This is where I am filtering the contacts
$criteria = Criteria::create()
->where(Criteria::expr()->eq("isDeleted", false));
return $this->contacts->matching($criteria);
}
然后我在控制器中使用JMS Serializer和FOSRest加载和序列化用户。
public function getUserAction($slug){
$data = $this->getDoctrine()->getRepository('MyCoreBundle:User')->find($slug);
$view = $this->view($data, 200);
return $this->handleView($view);
}
结果是以下JSON:
{
userId: 7,
creationDate: "2014-07-28T22:05:43+0000",
isActive: true,
username: "myUser",
contacts: [
{
contactId: 23,
firstName: "Jim",
lastName: "Bin",
email: "zzz@zzz.com",
phone: "1231231231",
isDeleted: true
}
]
}
我不确定为什么还在加载已删除的用户。如果我在我的控制器而不是Entity类中进行过滤,则过滤工作。但是我不希望在我的应用程序中随处可以加载 。如果我能在Entity类中获得某些功能,那将是理想的选择。有没有人做过类似的工作呢?
我正在使用Symfony 2.3
答案 0 :(得分:2)
我认为您的问题是当您从其存储库中获取用户时,getContacts
实际上没有被调用,这是使用标准的Doctrine查询完成的,并且因为用户和联系人是相关的无论联系人是否被删除,他们都会遇到。一种解决方案是使用findUserWithActiveContacts()
方法创建自己的UserRepository,该方法执行更合适的查询,并使用该方法。
例如:
UserRepository.php
namespace Demo\MyBundle\Entity;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
public function findWithActiveContacts($slug)
{
$result= $this->createQueryBuilder('u')
->join('u.contacts', 'c')
->select('u,c')
->where('c.isDeleted = false')
->andWhere('u.slug = :slug')
->setParameter('slug', $slug)
->getQuery()
->getResult();
return $result;
}
}
将实体连接到新存储库:
user.php的
class User{
/**
* @ORM\OneToMany(targetEntity="Contacts", mappedBy="user", cascade={"persist"}, fetch="EXTRA_LAZY")
* @ORM\JoinColumn(name="contact_id", referencedColumnName="contact_id")
* @ORM\Entity(repositoryClass="Demo\MyBundle\Entity\UserRepository")
*/
然后在控制器中:
public function getUserAction($slug){
$data = $this->getDoctrine()->getRepository('MyCoreBundle:User')->findWithActiveContacts($slug);
$view = $this->view($data, 200);
return $this->handleView($view);
}
因此,只要您使用findWithActiveContacts
代替find
,就应该始终只获取未删除的联系人,而无需更改任何其他内容。
我认为如果你愿意的话,你可能会在你的客户存储库中覆盖find
,但对你而言,这只会改变你所调用的方法的名称,而且我会担心其他代码(例如,为表单提取实体的东西)会开始使用它,这可能是你想要的,但也可能产生不可预测的后果。
以这种方式调整所有查询的官方Doctrine方法是使用Filters,它实际上在一个额外的where
条款中滑入了通过Doctrine的所有内容。这就是SoftDeleteable扩展的功能。
答案 1 :(得分:1)
我强烈推荐使用Soft-Deleteable扩展名。您必须使用deletedAt
字段,该字段在未删除对象时为null
,如果已删除,则为timestamp
。
它是这样的:
/**
* @ORM\Entity
* @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
*/
class User
{
/**
* @ORM\Column(name="deletedAt", type="datetime", nullable=true)
*/
private $deletedAt;
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
}
在此处查看此扩展程序:Soft-Deleteable Extension