Symfony2: inserting the one without the many of a one-to-many
我一直在努力使用 Symfony/Doctrine 方法来创建对象。目前的问题是如何最好地在一对多的一侧创建一个对象而不在多侧创建一个对象。问题似乎源于关系的拥有方,因此是对象是否持久化的决定因素。
详情:客户实体与成员实体是一对多的关系。客户端可以通过
自行创建
1 2 3 4 5 6 7 8 9 | $client = new Client(); $form = $this->createForm(new ClientType(), $client); $form->bind($request); if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($client); $em->flush(); return $this->redirect($this->generateUrl('client_show', array('id' => $client->getId()))); } |
和一个客户加上一个或多个成员,但不单独与
1 2 3 4 5 6 7 8 9 10 11 | $client = new Client(); $member = new Member(); $client->addMember($member); $form = $this->createForm(new ClientType(), $client); $form->bind($request); if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $member->setClient($client); $em->persist($member); $em->flush(); return $this->redirect($this->generateUrl('client_show', array('id' => $client->getId()))); |
客户实体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | class Client { /** * @var integer $id * * @ORM\\Column(name="id", type="integer", nullable=false) * @ORM\\Id * @ORM\\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @ORM\\OneToMany(targetEntity="Member", mappedBy="client") * */ protected $members; public function __construct() { $this->members = new ArrayCollection(); } public function getMembers() { return $this->members; } public function setMembers($members) { foreach ($members as $members) { $members->addClient($this); } $this->members = $members; return $this; } public function addMember(Member $member) { $this->members->add($member); // $member->setClient($this); return $this; // $this->members[] = $member; } public function removeMember(Member $member) { $this->members->removeElement($member); return $this; } |
成员实体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Member { /** * @var integer $id * * @ORM\\Column(name="hid", type="integer", nullable=false) * @ORM\\Id * @ORM\\GeneratedValue(strategy="IDENTITY") */ private $id; /** * @ORM\\ManyToOne(targetEntity="Client",inversedBy="members",cascade={"remove","persist"}) * @ORM\\JoinColumn(name="clientId", referencedColumnName="id") * */ protected $client; public function setClient(Client $client) { $this->client = $client; return $this; } public function getClient() { return $this->client; } |
如果没有插入成员,上面的代码会抛出错误。可以用一点代码来添加一个有或没有成员的客户端吗?
一个似乎涵盖两种情况的 createAction:有成员的客户端和没有成员的客户端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public function createAction(Request $request) { $client = new Client(); $form = $this->createForm(new ClientType(), $client); $form->bind($request); if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); $members = $client->getMembers(); foreach ($members as $member) { $member->setClient($client); $em->persist($member); } $em->persist($client); $em->flush(); return $this->redirect($this->generateUrl('client_show', array('id' => $client->getId()))); } return array( 'entity' => $client, 'form' => $form->createView(), ); |
Bind 获取表单数据并将其写入对象,然后该对象被持久化。
你叫:
1 | $client->addMember($member); |
bind 之前,本质上是给你的客户端添加了一个空对象,这似乎不是你想要做的。实际上,我希望第一个代码正是您想要的,但是您的 ClientType() 不正确。
我想你想要这样的东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php namespace ormed\\ormedBundle\\Form; use Symfony\\Component\\Form\\AbstractType; use Symfony\\Component\\Form\\FormBuilderInterface; use Symfony\\Component\\OptionsResolver\\OptionsResolverInterface; class ClientType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('ClientField' // one of several, probably ,null ,array() // specify options ) ->add('member' ,null ,array() // specify options ) ; } } |
添加
$builder->('member' ...
将成员选择器提供给表单,然后您的级联持久化应该处理其他所有事情。您可能希望将成员指定为实体类型并通过查询构建器构建列表。