Forms Symfony2-如何定义窗体和控制器以同时动态创建实体的多个对象?
Symfony2.7 我环顾四周,但没有找到一种简洁、标准的方式来定义: (*)一个表单(formType)和任何您需要的控制器,以允许用户动态地同时创建任意数量的对象 我看到了,但我无法复制他们的解决方案 问题是:是否有一个标准的方法来做(*) 注意:似乎没有帮助,因为它只创建一个唯一的任务对象,即使它允许用户(动态地)创建多个标记对象 部分解 以下方法很好:用户可以添加任意数量的对象 我需要检查我是否可以以某种方式清除代码。 如果你看到了改进的方法,请发表评论 最后,我希望有一个Job 1:M Tasks 1:M Tags的情况,用一个表单一次创建多个Job,每个Job有多个任务,每个任务有多个标签。我需要检查是否可以为相关的1:M实体嵌入表单。请继续收看 控制器Forms Symfony2-如何定义窗体和控制器以同时动态创建实体的多个对象?,forms,symfony,Forms,Symfony,Symfony2.7 我环顾四周,但没有找到一种简洁、标准的方式来定义: (*)一个表单(formType)和任何您需要的控制器,以允许用户动态地同时创建任意数量的对象 我看到了,但我无法复制他们的解决方案 问题是:是否有一个标准的方法来做(*) 注意:似乎没有帮助,因为它只创建一个唯一的任务对象,即使它允许用户(动态地)创建多个标记对象 部分解 以下方法很好:用户可以添加任意数量的对象 我需要检查我是否可以以某种方式清除代码。 如果你看到了改进的方法,请发表评论 最后,我希望有一个Job 1:
/**
* Creates a new Job entity.
*
* @Route("/", name="Myname_Job_create")
* @Method("POST")
* @Template("MynameBlogBundle:Job:new.html.twig")
*/
public function createAction(Request $request)
{
////var_dump($request); die('here'); // this helped a lot to understand
$postData = $request->request->get('form');
$entity = array();
foreach($postData['jobs'] as $key => $obj){$entity[$key]= new Job();}
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
try {
$em = $this->getDoctrine()->getEntityManager();
foreach($entity as $ent){ $em->persist($ent); }
$em->flush();
} catch (\Doctrine\DBAL\DBALException $e) {
die($e->getMessage());
}
return $this->redirect($this->generateUrl('Myname_Job'));
}
return array(
'info' => $postData,
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Creates a form to create a Job entity.
*
* @param Job $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Array $jobs)
{
$form = $this->createFormBuilder(array('jobs'=>$jobs))
->setAction($this->generateUrl('Myname_Job_create'))
->add('jobs','collection',array(
'required' => true,
'allow_add' => true,
'allow_delete' => true,
'type' => new JobType(),
))
->add('submit', 'submit',array('label' => 'Create'))
->getForm()
;
return $form;
}
/**
* Displays a form to create a new Job entity.
*
* @Route("/new", name="Myname_Job_new")
* @Method("GET")
* @Template()
*/
public function newAction()
{
$jobs = array(0 => new Job());
$form = $this->createCreateForm($jobs);
return array(
'entity' => $jobs,
'form' => $form->createView(),
);
}
工作类型
class JobType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text', array(
'label' => 'Write Title ',
'required' => true
))
->add('description','text',array(
'label' => 'Write Descr. ',
))
;
}
....
}
新的.twig模板
{% extends '::base.html.twig' %}
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('bundles/mynameblog/js/JQuery/jquery-2.1.0.js') }}" type="text/javascript">
</script>
<script>
var $collectionHolder;
// setup an "add aJobs" link
var $addJobLink = $('<a href="#" class="add_Job_link">Add Jobs</a>');
var $newLinkLi = $('<li></li>').append($addJobLink);
function addJobForm($collectionHolder, $newLinkLi) {
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a Jobs" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
}
jQuery(document).ready(function() {
// Get the ul that holds the collection of Jobs
$collectionHolder = $('ul.jobs');
// add the "add Jobs" anchor and li to the Jobs ul
$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addJobLink.on('click', function(e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a newJobs form (see next code block)
addJobForm($collectionHolder, $newLinkLi);
});
});
</script>
{% endblock %}
{% block main -%}
<h1>Job creation</h1>
{{ form_start(form) }}
<ul class="jobs" data-prototype="{{ form_widget(form.jobs.vars.prototype)|e }}">
{# render the job-s only two fields: title description #}
{% for f in form.jobs %}
<li> {{ form_row(f) }} </li>
{% endfor %}
</ul>
{{ form_end(form) }}
{% endblock %}
{%extends'::base.html.twig%}
{%block javascripts%}
{{parent()}}
var$collectionHolder;
//设置“添加aJobs”链接
变量$addJobLink=$('');
变量$newLinkLi=$(').append($addJobLink);
函数addJobForm($collectionHolder,$newLinkLi){
//获取前面解释的数据原型
var prototype=$collectionHolder.data('prototype');
//获取新索引
var索引=$collectionHolder.data('index');
//将原型HTML中的“\uuuu name\uuuuuu”替换为
//取而代之的是一个基于我们拥有多少物品的数字
var newForm=prototype.replace(/\uuuuu name\uuuuu/g,索引);
//为下一项增加索引1
$collectionHolder.data('index',index+1);
//在“添加一份工作”链接之前,在一个li页面中显示表单
变量$newFormLi=$('')。追加(newForm);
$newLinkLi.before($newFormLi);
}
jQuery(文档).ready(函数(){
//获取保存作业集合的ul
$collectionHolder=$('ul.jobs');
//将“添加工作”锚和li添加到工作列表中
$collectionHolder.append($newLinkLi);
//计算我们当前的表单输入(例如2),将其用作新的表单输入
//插入新项目时的索引(例如2)
$collectionHolder.data('index',$collectionHolder.find(':input').length);
$addJobLink.on('click',函数(e){
//阻止链接在URL上创建“#”
e、 预防默认值();
//添加newJobs表单(请参见下一个代码块)
addJobForm($collectionHolder,$newLinkLi);
});
});
{%endblock%}
{%块主-%}
创造就业机会
{{form_start(form)}}
{#仅呈现作业的两个字段:标题说明}
{form.jobs%]中的f的%s}
- {{form_row(f)}}
{%endfor%}
{{form_end(form)}}
{%endblock%}
建议:使用一个客户端操作添加多个对象的最佳方法:
- 为每个对象创建一个表单(只需用JS复制)
- 在JS中,收听submit按钮,并使用不同的ajax请求发送每个表单
- 如何创建实体
- 如何验证它们
我认为没有办法为“根”表单创建原型。您应该创建一个并使用javascript复制输入,更改输入名称。然后在控制器中,在将表单与请求绑定之前,您必须计算已发布的参数并重新生成扩展表单。@Alsatian,谢谢。我不知道如何更改输入名称,请参阅。还有,你所说的重建我的扩展表单是什么意思?@Alsatian,我的代码是否与你的思路一致?无论如何,谢谢。@Alsatian。非常感谢。我一有空就去看看。你认为它也适用于Symfony 2.7吗?(我不打算在不久的将来更新到v3)。是的,它应该在SF2.7中工作。只需使用类型的名称而不是类型的类。
class JobType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
// This is called once you posted your form to recreate the JS generated
// fiels on the server side. Otherwise, these fiels are ignorated
if($options['objects_count']>0){
for($i=0;$i<$options['objects_count'];$i++){
$builder
->add('title_'.$i, TextType::class)
->add('description_'.$i, TextType::class)
;
}
}
// This is called to render the first form
else{
$builder
->add('title', TextType::class)
->add('description', TextType::class)
;
}
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array('objects_count'=>0));
}
}
/**
* Creates a new Job entity.
*
* @Route("/", name="Myname_Job_create")
* @Method("POST")
* @Template("MynameBlogBundle:Job:new.html.twig")
*/
public function createAction(Request $request)
{
$i = 1;
$defaults = array();
while($request->request->has('title_'.$i)){
$defaults += array('title_'.$i=>"",'description_'.$i=>"");
$i++;
}
$objects_count = $i-1;
if($objects_count === 0){
$defaults = array('title'=>"",'description'=>"");
}
$form = $this->$defaults(JobType::class,$defaults,array('objects_count'=>$objects_count));
$form->handleRequest($request);
// ...
}