可以存储数组而不是映射的关联。在Symfony2中,使用collection Field Type相当容易。例如,使用此技术,您可以存储填充数组事件字段的文本字段数组。然而,为了更新数组,有一个技巧,@ Vadim Ashikhman在接受的答案中对这个技巧进行了精美的解释。
有时存储数组而不是映射关联是有用且高效的。但是,一旦创建,如果该数组的大小没有改变,更新此数组仍然很复杂吗?
许多人都有similar issue,但没有人找到解决此问题的正确方法。
团队可以组织许多活动。这些事件只是使用Doctrine而不是使用OneToMany关联存储在数组中。因此,实体事件不与Doctrine映射。
<?php
namespace Acme\TestBundle\Entity;
...
class Event
{
/**
* @Assert\NotBlank
*/
private $name;
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
<?php
namespace Acme\TestBundle\Entity;
...
/**
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks
* @ORM\Table(name="teams")
*/
class Team
{
/**
* @ORM\Column(type="array")
* @var array
*/
protected $events;
public function addEvent($event)
{
if (!in_array($event, $this->events, true)) {
$this->events[] = $event;
}
return $this;
}
public function removeEvent($event)
{
if (false !== $key = array_search($event, $this->events, true)) {
unset($this->events[$key]);
$this->events = array_values($this->events);
}
return $this;
}
public function getEvents()
{
return $this->events;
}
public function setEvents(array $events)
{
$this->events = array();
foreach ($events as $event) {
$this->addEvent($event);
}
return $this;
}
<?php
namespace Acme\TestBundle\Form\Type;
...
class EventType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('name', 'text');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TestBundle\Entity\Event',
'cascade_validation' => true,
));
}
...
}
<?php
namespace Acme\TestBundle\Form\Type;
...
class TeamType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('events','collection', array(
'type' => new EventType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
'options' => array('data_class' => 'Acme\TestBundle\Entity\Event'),
)
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TestBundle\Entity\Team',
));
}
...
}
/**
* Update a team
*
* @Route("update/{team_id}", name="updateTeamFromId")
* @Template("AcmeTestBundle:Team:teamUpdate.html.twig")
*/
public function updateTeamAction($team_id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$repository= $em->getRepository('AcmeTestBundle:Team');
$team_to_update = $repository->find($team_id);
$form = $this->createForm(new teamType(), $team_to_update);
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid()){
$em->persist($team_to_update);
$em->flush();
return $this->redirect($this->generateUrl('homepage')) ;
}
}
return array(
'form' => $form->createView(),
'team_id' => $team_id,
);
}
答案 0 :(得分:13)
你可以在这里找到答案:
How to force Doctrine to update array type fields?
参考文献:
Doctrine使用相同的运算符
===
来比较旧的变量 和新的价值观。操作员在同一个对象上使用 不同的数据总是返回true。还有另一种方法可以解决 在这个问题上,您可以克隆需要更改的对象。$items = $myEntityObject->getItems(); $items[0] = clone $items[0]; $items[0]->setSomething(123); $myEntityObject->setItems($items);
或者更改setItems()方法
public function setItems($items) { if (!empty($items) && $items === $this->items) { reset($items); $key = key($items); $items[$key] = clone $items[$key]; } $this->items = $items; }
答案 1 :(得分:2)
您可以在控制器内尝试:
public function updateTeamAction($team_id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$repository= $em->getRepository('AcmeTestBundle:Team');
$team_to_update = $repository->find($team_id);
$form = $this->createForm(new teamType(), $team_to_update);
if ($request->getMethod() == 'POST')
{
$form->bind($request);
if ($form->isValid()){
$events = $team_to_update->getEvents();
foreach($events as $key => $value){
$team_to_update->removeEvent($key);
}
$em->flush();
$team_to_update->setEvents($events);
$em->persist($team_to_update);
$em->flush();
return $this->redirect($this->generateUrl('homepage')) ;
}
}
return array(
'form' => $form->createView(),
'team_id' => $team_id,
);
}
可能有一种更好的方法可以做到这一点,我知道这不是一个很好的方法,但除非你(或其他人)找到解决方案,你可以使用它作为临时修复。