Symfony:嵌入ManyToOne-OneToMany关系的表单集合 [英] Symfony: Embed collection of forms for ManyToOne-OneToMany relation

查看:197
本文介绍了Symfony:嵌入ManyToOne-OneToMany关系的表单集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运行Symfony 2.3与Doctrine以及这三个(相关)实体:出版作者 AuthorPublication
两者,作者出版物 AuthorPublication 具有多对一关系(所以它基本上是一个多对多关系, 作者发布之间的许多关系,但是我需要 AuthorPublication 实体来命令发布作者)



我想要一个用户可以创建新出版物的表单,并根据需要为该出版物选择尽可能多的作者。



我研究过这篇文章:如何嵌入表单集合,但我不明白如何将其应用于我的问题,因为 AuthorPublication 实体之间。



相关代码:



出版物

 <?php 

命名空间ind\PubBundle\Entity;

使用Doctrine\ORM\Mapping作为ORM;

/ **
* @ ORM\Entity(repositoryClass =ind\PubBundle\Repository\PublicationRepository)
* @ ORM\Table(出版物)
* /
class出版物{

/ **
* @ ORM\Column(type =integer)
* @ORM \Id
* @ ORM\GeneratedValue(strategy =AUTO)
* /
protected $ pid;

/ **
* @ ORM\OneToMany(targetEntity =AuthorPublication,mappedBy =publication)
* @ ORM\OrderBy({order_id= ASC})
* /
protected $ publicationAuthors;


//一些更多属性+ getters / seters
?>

作者

 <?php 

命名空间ind\PubBundle\Entity;

使用Doctrine\ORM\Mapping作为ORM;

/ **
* @ ORM\Entity
* @ ORM\Table(aid_author)
* /
类作者{

/ **
* @ ORM\Column(type =integer)
* @ ORM\Id
* @ ORM\GeneratedValue(strategy = AUTO)
* /
protected $ aid;

/ **
* @ ORM\Column(type =string,length = 255)
* /
protected $ author_surname;

/ **
* @ ORM\Column(type =string,length = 255)
* /
protected $ author_forename;

/ **
* @ ORM\OneToMany(targetEntity =AuthorPublication,mappedBy =author)
* /
protected $ authorPublication;
?>

作者公开

 <?php 

命名空间ind\PubBundle\Entity;

使用Doctrine\ORM\Mapping作为ORM;

/ **
* @ ORM\Entity
* @ ORM\Table(aid_pid)
* /
class AuthorPublication {

/ **
* @ ORM\Id
* @ ORM\Column(type =integer)
* /
protected $ aid ;

/ **
* @ ORM\Id
* @ ORM\Column(type =integer)
* /
protected $ PID;

/ **
* @ ORM\Column(type =integer)
* /
protected $ order_id;

/ **
* @ ORM\ManyToOne(targetEntity =Publication,inversedBy =publicationAuthors)
* @ ORM\JoinColumn(name =pid ,referencedColumnName =pid)
* /
protected $ publication;

/ **
* @ ORM\ManyToOne(targetEntity =Author,inversedBy =authorPublication)
* @ ORM\JoinColumn(name =aid ,referencedColumnName =aid)
* /
protected $ author;
?>


解决方案


  1. 你必须创建一个AuthorPublicationType表单。您将字段作者作为实体和您的其他字段...


  2. 您的出版物类型包括AuthorPublication(嵌入式表单)。


  3. 然后,您可以添加新的AuthorPublication与原型和非常简单的javascript


  4. 请注意,当您必须先保存您的实体出版物时,authorPublication属性为null。并且在更新之后,使用出版物和LifecycleCallbacks中使用临时ArrayCollection定义的authorPublication。


编辑:示例。 / p>

我的实体是Sport OneToMany SportParam ManyToOne ConfigParam。 SportParam由Sport,ConfigParam和值组成。



我想用多个ConfigParam创建一个新的Sport:


  1. SportParamType:

      public function buildForm(FormBuilderInterface $ builder,array $选项)
    {
    $ builder
    - > add('ConfigParam','entity',array(
    'class'=>'PPHBSportScoringBundle:ConfigParam',
    'property'=>'nom',
    'multiple'=> false,
    'label'=>'Paramètre'
    ))
    - > add('valeur','number',array('precision'=> 2))
    ;
    }


  2. SportType



    public function buildForm(FormBuilderInterface $ builder,array $ options)
    {
    $ builder
    - > add('nom')
    - > add('SportParams','collection',array(
    'type'=> new SportParamType(),
    'allow_add'=> true,
    'allow_delete '=> true,
    'by_reference'=> false
    ))
    ;

    }


  3. 我的form.html.twig: p>

      {{form_start(form)}} 
    {{form_errors(form)}}
    {{form_row form.nom)}}
    < ul class = SportParams data-prototype ={{form_widget(form.SportParams.vars.prototype)| e}}>
    {%for form.SportParams%}
    < li>
    {{form_errors(param.ConfigParam)}}
    {{form_widget(param.ConfigParam)}}
    {{form_errors(param.valeur)}}
    {{form_widget param.valeur)}}
    < / li>
    {%endfor%}
    < / ul>
    < input type =submitclass =btn btn-primary/>
    {{form_end(form)}}

    我的Javascript改进,因为它包含更多的代码AJAX调用)。它可能包含一些错误。如果不清楚,请查看文档

     < script type =text / javascript> 

    $ var $ container = $('ul.SportParams');
    //按钮添加一个新的SportParam
    var $ addSportParamLink = $('< a href =#id =ajout_paramclass =btn btn-primary btn-xs> Ajouter unparamètre< / a>');
    var $ newLinkLi = $('< li>< / li>')。append($ addSportParamLink);

    $(document).ready(function(){
    //每个现有的SportParam
    $ container.find('li')上的删除按钮each(function() {
    addParamFormDeleteLink($(this));
    });

    //添加按钮
    $ container.append($ newLinkLi);

    //在添加按钮时添加新表单添加按钮
    $ addSportParamLink.on('click',function(e){
    e.preventDefault(); //évitequ'un #apparaisse dans l'URL
    var index = $ container.children()。length-1;

    addParamForm($ container,$ newLinkLi);

    var bAffiche;

    return false;
    });

    //添加新的表单SportParam
    函数addParamForm($ container,$ newLinkLi){

    var $ prototype = $ container.attr('data-prototype');

    var newForm = $ prototype.replace(/ __ name __ / g,$ container.children() 1);

    var $ newFormLi = $('< ;李>< /立GT;)附加(newForm);
    $ newLinkLi.before($ newFormLi);

    addParamFormDeleteLink($ newFormLi);
    }

    函数addParamFormDeleteLink($ paramFormLi){
    var $ removeFormA = $('< a href =#class =btn btn-danger btn-xs > Supprimer< / A>');
    $ paramFormLi.append($ removeFormA);
    $ removeFormA.on('click',function(e){
    e.preventDefault();
    $ paramFormLi.remove();
    });
    }

    });
    < / script>


  4. 运动实体通话回来:

      / ** 
    * sport
    *
    * @ ORM\Table()
    * @ ORM\Entity
    * @ ORM\HasLifecycleCallbacks
    * @ ORM\Entity(repositoryClass =SportRepository)
    * /
    class Sport
    {

    。 ..实体属性...

    / **
    * @var ArrayCollection
    *
    *保存Sport没有SportParams
    * /
    私人$ SportParamsTMP;

    ... getter和setter ...

    / **
    * @ ORM\PrePersist
    * /
    public function saveSportParams()
    {
    $ this-> SportParamsTMP = $ this-> SportParams;
    $ this-> SportParams = null;
    }
    / **
    * @ ORM\PostPersist
    * /
    public function restoreSportParams()
    {
    if($ this - > SportParamsTMP ==!null){
    $ this-> SportParams = $ this-> SportParamsTMP;
    }
    $ this-> SportParamsTMP = null;
    }

    }

    最后控制器的功能添加一个新的运动:

      public function addAction()
    {
    $ sport = new Sport ;
    $ form = $ this-> createForm(new SportType(),$ sport);

    $ request = $ this-> getRequest();

    if($ request-> getMethod()==POST){
    $ form-> bind($ request);
    if($ form-> isValid()){
    $ em = $ this-> getDoctrine() - > getManager();

    $ em-> persist($ sport);
    //保存运动没有参数
    $ em-> flush();

    //更新参数
    $ em-> flush();

    return $ this-> redirect($ this-> generateUrl('pphb_sport_liste'));
    }
    }

    return $ this-> render('PPHBSportScoringBundle:Championnat / Sport:add.html.twig',array(
    'form'= > $ form-> createView(),
    ));
    }


我希望它有帮助。

不知道这是否是最好的方法,但它对我来说是有效的。如果有什么改进让我知道。


I am running Symfony 2.3 with Doctrine and these three (relevant) entities: Publication, Author and AuthorPublication. Both, Author and Publication have a Many-to-One relationship to AuthorPublication (so it is basically a Many-to-Many relation between Author and Publication but I need the AuthorPublication Entity to order the authors of a publication)

I want to have a form where a user can create a new publication and choose as many authors for that publication as he wants.

I studied this article: How to Embed a Collection of Forms but I do not understand how to apply that to my problem because of the AuthorPublication entity which lies in between.

Relevant Code:

Publication

<?php

namespace ind\PubBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="ind\PubBundle\Repository\PublicationRepository")
 * @ORM\Table("publications")
 */
class Publication {

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $pid;

    /**
     * @ORM\OneToMany(targetEntity="AuthorPublication", mappedBy="publication")
     * @ORM\OrderBy({"order_id" = "ASC"})
     */
    protected $publicationAuthors;


//some more attributes + getters/seters
?>

Author

<?php

namespace ind\PubBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table("aid_author")
 */
class Author {

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $aid;

    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $author_surname;

    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $author_forename;

    /**
     * @ORM\OneToMany(targetEntity="AuthorPublication", mappedBy="author")
     */
    protected $authorPublication;
?>

AuthorPublication

<?php

namespace ind\PubBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table("aid_pid")
 */
class AuthorPublication {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     */
    protected $aid;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     */
    protected $pid;

    /**
     * @ORM\Column(type="integer")
     */
    protected $order_id;

    /**
     * @ORM\ManyToOne(targetEntity="Publication", inversedBy="publicationAuthors")
     * @ORM\JoinColumn(name="pid", referencedColumnName="pid")
     */
    protected $publication;

    /**
     * @ORM\ManyToOne(targetEntity="Author", inversedBy="authorPublication")
     * @ORM\JoinColumn(name="aid", referencedColumnName="aid")
     */
    protected $author;
?>

解决方案

  1. You have to make an AuthorPublicationType form. You put field author as an 'entity' and your others fields...

  2. You make your PublicationType including AuthorPublication (Embedded Forms).

  3. Then you can add new AuthorPublication with prototype and very simple javascript.

  4. Note that when you have to save your entity Publication with an authorPublication attribut null first. And after update Publication with authorPublication defined by using temporary ArrayCollection in Publication and LifecycleCallbacks for example.

EDIT : Example.

My entities are Sport OneToMany SportParam ManyToOne ConfigParam. SportParam is composed of a Sport, a ConfigParam and a value.

I want to create a new Sport with multiple ConfigParam :

  1. SportParamType :

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder        
            ->add('ConfigParam', 'entity', array(
                'class'    => 'PPHBSportScoringBundle:ConfigParam',
                'property' => 'nom',
                'multiple' => false,
                'label'=>'Paramètre'
            ))
            ->add('valeur','number',array('precision'=>2))
        ;
    }
    

  2. SportType

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('nom')
            ->add('SportParams',  'collection', array(
                'type'=> new SportParamType(),
                'allow_add'    => true,
                'allow_delete' => true,
                'by_reference'=> false
            ))
        ;
    
    }
    

  3. My form.html.twig :

    {{ form_start(form) }}
      {{ form_errors(form) }} 
      {{ form_row(form.nom) }}
      <ul class=SportParams data-prototype="{{ form_widget(form.SportParams.vars.prototype)|e }}">
        {% for param in form.SportParams %}
          <li>
          {{ form_errors(param.ConfigParam) }}
          {{ form_widget(param.ConfigParam) }}
          {{ form_errors(param.valeur) }}
          {{ form_widget(param.valeur) }}
          </li>
        {% endfor %}
      </ul>
      <input type="submit" class="btn btn-primary" />
    {{ form_end(form) }}
    

    My Javascript refine because it contains more code (AJAX call). It maybe contains some mistake. If it's not clear have a look to the documentation :

    <script type="text/javascript">
    
    var $container = $('ul.SportParams');
    // button to add a new SportParam
    var $addSportParamLink = $('<a href="#" id="ajout_param" class="btn btn-primary btn-xs">Ajouter un paramètre</a>');  
    var $newLinkLi = $('<li></li>').append($addSportParamLink);
    
    $(document).ready(function() {
        //delete button on each existing SportParam
        $container.find('li').each(function() {
            addParamFormDeleteLink($(this));
        });       
    
        //add button
        $container.append($newLinkLi);
    
        // adding a new form when cliking Add button
        $addSportParamLink.on('click',function(e) {         
            e.preventDefault(); // évite qu'un #apparaisse dans l'URL
            var index = $container.children().length-1;
    
            addParamForm($container,$newLinkLi);
    
            var bAffiche; 
    
            return false;
        });
    
        // adding a new form SportParam
        function addParamForm($container, $newLinkLi) {
    
            var $prototype = $container.attr('data-prototype');
    
            var newForm = $prototype.replace(/__name__/g, $container.children().length-1);  
    
            var $newFormLi = $('<li></li>').append(newForm);
            $newLinkLi.before($newFormLi);
    
            addParamFormDeleteLink($newFormLi);
        }
    
        function addParamFormDeleteLink($paramFormLi){
            var $removeFormA = $('<a href="#" class="btn btn-danger  btn-xs">Supprimer</a>');   
            $paramFormLi.append($removeFormA);
            $removeFormA.on('click', function(e) {
                e.preventDefault();
                $paramFormLi.remove();
            });
        }
    
    });
    </script>
    

  4. Sport Entity call's back :

    /**
     * sport
     *
     * @ORM\Table()
     * @ORM\Entity
     * @ORM\HasLifecycleCallbacks
     * @ORM\Entity(repositoryClass="SportRepository")
     */
    class Sport
    {
    
    ...Entity attribut...
    
        /**
         * @var ArrayCollection
         *
         * To save Sport without SportParams
         */
        private $SportParamsTMP;
    
    ...getter and setter ...
    
        /**
         * @ORM\PrePersist
         */
        public function saveSportParams()
        {   
          $this->SportParamsTMP = $this->SportParams;
          $this->SportParams = null;
        }
        /**
         * @ORM\PostPersist
        */
        public function restoreSportParams()
        {
          if ($this->SportParamsTMP == !null) {
            $this->SportParams = $this->SportParamsTMP;
          }
          $this->SportParamsTMP = null;
        }
    
    }   
    

    Finally the controller 's function to add a new Sport :

    public function addAction()
    {
      $sport = new Sport();
      $form = $this->createForm(new SportType(), $sport);
    
      $request = $this->getRequest();
    
      if ($request->getMethod() == "POST") {
        $form->bind($request);
        if($form->isValid()) {
          $em = $this->getDoctrine()->getManager();
    
          $em->persist($sport);
          //saving sport without parameter
          $em->flush();
    
          //updating sport with parameter
          $em->flush();
    
          return $this->redirect($this->generateUrl('pphb_sport_liste'));
        }
      }
    
      return $this->render('PPHBSportScoringBundle:Championnat/Sport:add.html.twig', array(
                 'form' => $form->createView(),
      ));
    }
    

I hope it help.
Don't know if it's the best way to do it, but it's working for me. If something to improve let me know please.

这篇关于Symfony:嵌入ManyToOne-OneToMany关系的表单集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆