Forms Symfony2-如何定义窗体和控制器以同时动态创建实体的多个对象?

Forms Symfony2-如何定义窗体和控制器以同时动态创建实体的多个对象?,forms,symfony,Forms,Symfony,Symfony2.7 我环顾四周,但没有找到一种简洁、标准的方式来定义: (*)一个表单(formType)和任何您需要的控制器,以允许用户动态地同时创建任意数量的对象 我看到了,但我无法复制他们的解决方案 问题是:是否有一个标准的方法来做(*) 注意:似乎没有帮助,因为它只创建一个唯一的任务对象,即使它允许用户(动态地)创建多个标记对象 部分解 以下方法很好:用户可以添加任意数量的对象 我需要检查我是否可以以某种方式清除代码。 如果你看到了改进的方法,请发表评论 最后,我希望有一个Job 1:

Symfony2.7

我环顾四周,但没有找到一种简洁、标准的方式来定义:

(*)一个表单(formType)和任何您需要的控制器,以允许用户动态地同时创建任意数量的对象

我看到了,但我无法复制他们的解决方案

问题是:是否有一个标准的方法来做(*)

注意:似乎没有帮助,因为它只创建一个唯一的任务对象,即使它允许用户(动态地)创建多个标记对象

部分解 以下方法很好:用户可以添加任意数量的对象

我需要检查我是否可以以某种方式清除代码。 如果你看到了改进的方法,请发表评论

最后,我希望有一个Job 1:M Tasks 1:M Tags的情况,用一个表单一次创建多个Job,每个Job有多个任务,每个任务有多个标签。我需要检查是否可以为相关的1:M实体嵌入表单。请继续收看

控制器

/**
 * 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请求发送每个表单
    所以很简单。。。 无需使用复杂的表单por来管理接收已发布请求的控制器中的多个实体

    但是,要做你想做的事:

    这里有一个方法来做你想做的事。 我只强调了如何在服务器端调整表单。 我无法测试您的JS,这里我假设它在您的表单中添加了[title_1,description_1,title_2,description_2,…]等字段

    你还应该适应:

    • 如何创建实体
    • 如何验证它们
    我建议您使用“对象计数”选项调整表单: (请注意,您应该处理没有类的表单(不应在configureOptions中定义数据类))


    我认为没有办法为“根”表单创建原型。您应该创建一个并使用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);
    
        // ...
    }