学说模块:实体关系是水合但不坚持实体

时间:2014-11-11 19:55:02

标签: php doctrine-orm doctrine

我在用户(拥有方)和用户组之间存在多对多的关系,并且在使用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;
    }
}

2 个答案:

答案 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)