1

我正在尝试通过单个表单提交将用户实体与配置文件实体保持一致。按照Doctrine2 文档中的说明并添加其他属性后,这似乎足以实现目标。

实体

按照规定设置实体非常简单,结果如下(我省略了生成的 getter/setter):

// ...

/**
 * @ORM\Entity
 */
class User
{
  /**
   * @ORM\Id
   * @ORM\Column(type="integer")
   * @ORM\GeneratedValue
   */
  private $id;

  /**
   * @ORM\Column(type="string", length=64)
   */
  private $data;

  /**
   * @ORM\OneToOne(targetEntity="Profile", mappedBy="user", cascade={"persist", "remove"})
   */
  private $Profile;

  // ...
}

// ...

/**
 * @ORM\Entity
 */
class Profile
{
  /**
   * @ORM\Id
   * @ORM\OneToOne(targetEntity="User")
   */
  private $user;

  /**
   * @ORM\Column(type="string", length=64)
   */
  private $data;

  // ...
}

形式

现在修改表格也不太难:

// ...

class ProfileType extends AbstractType
{
  public function buildForm(FormBuilder $builder, array $options)
  {
      $builder
          ->add('data')
      ;
  }

  public function getName()
  {
      return 'profile';
  }

  public function getDefaultOptions(array $options)
  {
      return array('data_class' => 'Acme\TestBundle\Entity\Profile');
  }
}

// ...

class TestUserType extends AbstractType
{
  public function buildForm(FormBuilder $builder, array $options)
  {
      $builder
          ->add('data')
          ->add('Profile', new ProfileType())
      ;
  }

  public function getName()
  {
      return 'user';
  }
}

控制器

class UserController extends Controller
{
  // ...

  public function newAction()
  {
      $entity = new User();
      $form   = $this->createForm(new UserType(), $entity);

      return array(
          'entity' => $entity,
          'form'   => $form->createView()
      );
  }

  public function createAction()
  {
      $entity  = new User();
      $request = $this->getRequest();
      $form    = $this->createForm(new UserType(), $entity);
      $form->bindRequest($request);

      if ($form->isValid()) {
          $em = $this->getDoctrine()->getEntityManager();
          $em->persist($entity);
          $em->flush();

          return $this->redirect($this->generateUrl('user_show',
              array('id' => $entity->getId())));

      }

      return array(
          'entity' => $entity,
          'form'   => $form->createView()
      );
    }

    // ...
}    

但现在是进行测试的部分。我开始创建一个新的用户对象,嵌入的表单按预期显示,但点击提交返回:

例外

Acme\TestBundle\Entity\Profile 类型的实体缺少分配的 ID。此实体的标识符生成策略要求在调用 EntityManager#persist() 之前填充 ID 字段。如果您想要自动生成标识符,则需要相应地调整元数据映射。

我已经知道的一个可能的解决方案是为 Profile 实体上的独立主键添加一个附加列。

但是我想知道是否有一种方法可以使映射保持大致相同但处理保留嵌入式表单?

4

2 回答 2

2

在通过 IRC 与几个人讨论了一段时间后,我修改了映射并提出了这个:

实体

// ...

/**
 * @ORM\Entity
 */
class User
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=64)
     */
    private $data;

    /**
     * @ORM\OneToOne(targetEntity="Profile", cascade={"persist", "remove"})
     */
    private $Profile;

    // ...
}

// ...

/**
 * @ORM\Entity
 */
class Profile
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=64)
     */
    private $data;

    // ...

}    

那么这有什么变化呢?首先,我删除了关系的 mappedBy 和 inversedBy 选项。此外,不需要 Profile-entity 上的 OneToOne 注释。

用户和个人资料之间的关系可以是双向的,但是以用户为拥有方的单向关系足以控制数据。由于级联选项,您可以确保没有没有用户的剩余配置文件,并且用户可以维护配置文件但不必这样做。

如果您想使用双向关系,我建议您查看Github:Doctrine2 - Tests - DDC117并特别注意 Article 和 ArticleDetails 的 OneToOne 关系。但是,您需要注意,从测试文件(评论中提供的链接)可以看出,保存这种双向关系有点棘手:您需要首先保留文章并在ArticleDetails::__construct中相应地设置构造函数涵盖关系的双向性质。

于 2012-06-13T03:46:10.887 回答
0

我所看到的问题是您只是在创建/保存一个用户对象。

由于用户/个人资料是一对一的关系(用户是拥有方)是否可以安全地假设用户将始终具有个人资料关系,因此可以在用户构造中初始化

class User 
{
    public function __construct()
    {
        $this->profile = new Profile();
    }
}

毕竟,您已将 User 设置为级联相关 Profile 对象的持久性。这将使您的实体经理创建两个实体并建立关系。

于 2012-06-08T12:45:28.523 回答