我在用户(拥有方)和用户组之间存在多对多的关系,并且在使用doctrine模块的水合器来创建新用户组时遇到了问题。
当我创建一个新的用户组并进行水合,持久化和刷新时,数据库中的记录会发生变化,但代表用户组的实体变量本身并不会在水合后的任何用户中结束。
上下文:我们有一个REST控制器路由,用于通过POST创建新的用户组。它接受参数以通过水合作用对一些用户进行初始化。此操作成功更新数据库,但其响应不正确。它应该从现在持久的实体中提取数据并将其回送给客户端。但是,它无法提取任何用户,因此响应错误地返回为空组。不使用水化器的提取方法,而是使用更基本的学说命令也失败了 - 似乎实体变量本身在被持久化后不会保持最新状态。
所以我的问题确实是:为什么保湿器没有提取用户?如果我们搞乱了所有者/反向关联,为什么它会起作用(即持久化用户)数据库但不是实体)。
这是相关代码,可能只需要前两个块。
public function create($data) {
...
$hydrator = $this->getHydrator();
$em = $this->getEntityManager();
$entity = $this->getEntity();
$entity = $hydrator->hydrate($data, $entity);
// Persist the newly created entity
$em->persist($entity);
// Flush the changes to the database
$em->flush();
return $this->createResponse(
201,
true,
'Created item',
$this->getHydrator()->extract($entity)
);
以下是保湿器使用的定位器和吸气剂:
... more fields...
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="groups")
*/
protected $users;
...
/**
* Getter for users
*
* @return mixed
*/
public function getUsers() {
return $this->users;
}
public function addUsers(Collection $users) {
foreach ($users as $user) {
$user->addGroups(new ArrayCollection(array($this)));
}
}
我认为以上是唯一相关的代码,但我会在错误的情况下包含更多内容。这是getHydrator方法:
public function getHydrator() {
if(null === $this->hydrator) {
$hydrator = new DoctrineObject($this->getEntityManager(), $this->getEntityName());
// Use Entity metadata to add extraction stategies for associated fields
$metadata = $this->em->getClassMetadata($this->getEntityName());
foreach ($metadata->associationMappings as $field => $mapping) {
// Use our custom extraction strategies for single and collection valued associations
if($metadata->isSingleValuedAssociation($field)) {
$hydrator->addStrategy($field, new RestfulExtractionStrategy());
}
else if($metadata->isCollectionValuedAssociation($field)) {
$hydrator->addStrategy($field, new RestfulExtractionCollectionStrategy());
}
}
$this->hydrator = $hydrator;
}
return $this->hydrator;
}
这是RestfulExtractionCollectionStrategy(这里没有使用其他策略,我已经验证了这一点。)
namespace Puma\Controller;
use DoctrineModule\Stdlib\Hydrator\Strategy\AllowRemoveByValue;
use Doctrine\Common\Collections\Collection;
/**
* You can use this strategy with fields that are collections,
* e.g. one to many. You need to use the RestfulExtractionStrategy
* if you want to get extract entities from a singleton field, e.g. manyToOne.
**/
class RestfulExtractionCollectionStrategy extends AllowRemoveByValue
{
public function extract($value)
{
if ($value instanceof Collection) {
$return = array();
foreach ($value as $entity) {
if(method_exists($entity, 'getId')){
$return[] = $entity->getId();
}
else {
$return[] = $entity;
}
}
return $return;
}
return $value;
}
}
答案 0 :(得分:0)
我想我终于解决了这个问题 - 我在“setter”方法addUsers
中添加了一行,它在更新相关用户后手动更新了组的用户属性。不过,如果这是最好的做法,我会有点惊讶。我原以为更新拥有方(用户)会自动更新反面(用户组)。也许我错了。 如果其他人有更好的主意,我很乐意将答案归功于他们。
public function addUsers(Collection $users) {
foreach ($users as $user) {
$user->addGroups(new ArrayCollection(array($this)));
// This is the new line (updating the usergroup property manually)
$this->users->add($user);
}
}
答案 1 :(得分:0)
我对水合作用等不太熟悉,因此您的代码对我来说有点奇怪,我不能保证这会起作用,但是您是否尝试在刷新后刷新实体(即$em->refresh($entity)
)并也许返回实体而不是$this->getHydrator()->extract($entity)
?