这与我之前关于嵌入式表单的问题有关。按照建议,我切换到树枝模板,现在一切都按预期显示,添加新空表单的链接正常工作。问题是当我尝试保存新记录时,它不起作用(尽管保存了对现有实体的编辑)。
有几点我可能出错了,所以我会在进行过程中提出问题。
这里有一些背景:
一项研究可以有许多参与者(即,研究实体与实体参与者具有 OneToMany 关系)。在数据库中,每个 Participant 记录都有从“study”列到 Study 表中记录的“study_id”列的外键链接,使其成为关系的拥有方。类中的注释应该反映这种关系。
学习班:
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CRUK\MyBundle\Entity\Study
*
* @ORM\Table(name="study")
* @ORM\Entity
*/
class Study
{
/**
* @var integer $id
*
* @ORM\Column(name="study_id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var string $studyName
*
* @ORM\Column(name="study_name", type="string", length=50, nullable=false)
*/
private $studyName;
/*
* @ORM\OneToMany(targetEntity="Participant", mappedBy="study", cascade={"persist"})
*
* @var ArrayCollection $participants
*/
protected $participants;
public function __construct()
{
$this->participants = new ArrayCollection();
}
public function setParticipants(ArrayCollection $participants)
{
foreach($participants as $participant) {
$participant->setStudy($this);
}
$this->participants = $participants;
}
/**
* @return ArrayCollection A Doctrine ArrayCollection
*/
public function getParticipants()
{
return $this->participants;
}
}
我的参与者班级:
namespace MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CRUK\SampleTrackingBundle\Entity\Participant
*
* @ORM\Table(name="participant")
* @ORM\Entity
*/
class Participant
{
/**
* @var integer $id
*
* @ORM\Column(name="participant_id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
...
/**
* @var study
*
* @ORM\ManyToOne(targetEntity="Study", inversedBy="participants")
* @ORM\JoinColumn(name="study", referencedColumnName="study_id")
*
*/
private $study;
//setters and getters...
}
首先,这些注释是否正确?(我很确定我脑子里有整个拥有/反向多对一/一对多关系,但我可能弄错了)
我的控制器:
Class StudyController extends Controller
{
...
public function addParticipantsAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('MyBundle:Study')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Study id='.$id);
}
$participantArray = $em->getRepository('MyBundle:Participant')->findByStudy($id);
//this is supposed to return a Doctrine ArrayCollection, but for some reason, returns an array
// This needs to be converted to an ArrayCollection
$participants = new ArrayCollection();
foreach ($participantArray as $participant) {
$participants->add($participant);
}
$entity->setParticipants($participants);
$form = $this->createForm(new StudyType(), $entity);
$request = $this->getRequest();
if ('POST' === $request->getMethod()) {
$form->bindRequest($request);
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
}
}
return $this->render('MyBundle:Study:addParticipants.html.twig', array(
'form' => $form->createView(),
'entity' => $entity
));
}
...
}
此时我要问为什么需要显式获取参与者的集合并使用它来设置研究实体上的集合?在我添加该代码之前,$entity->getParticipants() 将返回 null(即使我知道有几个参与者为研究设置了外键)。我在多对多关系中还有另外两个表,其中集合似乎只是通过在实体类中具有正确的注释而自动出现。这是多对多映射与多对一之间的区别,还是我以某种方式弄乱了注释?
我不确定其余的代码是否会有所帮助,但还有更多:我的学习表格类:
class StudyType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('studyName', null, array('label'=> 'Study Name:'))
->add('participants', 'collection', array(
'type'=> new ParticipantType(),
'allow_add'=>true,
'by_reference'=>false
));
}
public function getName()
{
return 'study';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'MyBundle\Entity\Study',
);
}
}
我的嵌入式表单类:
class ParticipantType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('participantId','text', array('label'=>'Participant ID'))
));
}
public function getName()
{
return 'participant';
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'MyBundle\Entity\Participant',
);
}
}
我的模板:
{% extends 'MyBundle::base.html.twig' %}
{% block body%}
<form action="{{ path('study_addparticipants', { 'id': entity.id }) }}" method="POST" {{ form_enctype(form) }}>
<!-- renders global errors -->
{{ form_errors(form) }}
<h2>Study</h2>
{{ form_label(form.studyName) }}
{{ form_errors(form.studyName) }}
{{ form_widget(form.studyName) }}
<h3>Participants in this study</h3>
<ul class="participants" data-prototype="{{ form_widget(form.participants.get('prototype')) | e }}">
{% for participant in form.participants %}
<li>{{form_row(participant) }}</li>
{% endfor %}
</ul>
{{ form_rest(form) }}
<button type="submit">Save Changes</button>
</form>
{% endblock%}
{% block javascripts %}
{# parent block includes jQuery #}
{{ parent() }}
<script type='text/javascript'>
jQuery(document).ready(function() {
// keep track of how many participant fields have been rendered
var collectionHolder = $('ul.participants');
var $addLink = $('<a href="#" class="add_participant_link">Add new Participant</a>');
var $newLinkLi = $('<li></li>'). append($addLink);
collectionHolder.append($newLinkLi);
$addLink.on('click', function(e) {
e.preventDefault();
addParticipantForm(collectionHolder, $newLinkLi);
});
});
function addParticipantForm(collectionHolder, $newLinkLi) {
// Get the data-prototype we explained earlier
var prototype = collectionHolder.attr('data-prototype');
// Replace '$$name$$' in the prototype's HTML to
// instead be a number based on the current collection's length.
var newForm = prototype.replace(/\$\$name\$\$/g, collectionHolder.children().length);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
}
</script>
{% endblock %}
因此,表单正确显示,当我单击“添加新参与者”链接时,会附加一个空的参与者表单。保存对研究和现有参与者记录的更改。没有错误,但不会保存任何新参与者。
我已经阅读了许多与此问题类似的问题,据我所知,包含了应该使这项工作正常进行的所有内容。我显然错过了一些东西,所以如果有任何关于如何解决这个问题的建议,我将不胜感激。
非常感谢。