一对多的属性,具有Symfony 3 / Doctrine形式的表单 [英] One-to-Many-to-One with attributes Form with Symfony 3 / Doctrine

查看:89
本文介绍了一对多的属性,具有Symfony 3 / Doctrine形式的表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题出在这里:



我有一个具有3个类的模型




  • person

  • person_job

  • job



一个人可以有多个工作,任何工作-人际关系都可以具有 date_start属性, date_end和 comment。因此,我使用持有这些属性的可接合(person_job)构建了该模型,并在2个名为person和job的manyToOne属性(通过教义注释生成)上建立了关系



Person属性看起来像:

  / ** 
* @var string
* @ ORM\Column(name = name,type = string,length = 255,nullable = false)
* /
private $ name;

/ **
* @变量字符串
* @ ORM\Column(name = firstname,type = string,length = 255,nullable = true)
* /
私人$ firstname;
/ **
* @var bool
* @ ORM\Column(name = active,type = boolean)
* /
private $活性;

工作属性如下:

  / ** 
* @var字符串
* @ ORM\Column(name = name,type = string,length = 255,nullable = false )
* /
私人$ name;

person_job看起来像这样:

  / ** 
* @ ORM\ManyToOne(targetEntity = ... \Person)
* @ ORM\JoinColumn(nullable = false)
* /
私人$ person;

/ **
* @ ORM\ManyToOne(targetEntity = ... \Job)
* @ ORM\JoinColumn(nullable = false)
* /
私人$ job;

/ **
* @var字符串
* @ ORM\Column(name = comment,type = string,length = 255,nullable = true)
* /
私人评论;

/ **
* @var \DateTime
* @ ORM\Column(name = startdate,type = datetime)
* /
private $ datestart;

/ **
* @var \DateTime
* @ ORM\Column(name = enddate,type = datetime)
* /
私人$ dateend;

现在我想为我的人建立一个表格,我可以在其中选择工作列表,然后添加(如果需要)与此作业相关的date_start,date_end或注释。对于人,我的FormBuilder看起来像这样:

  $ builder 
-> add('name')
-> add('first'')
-> add('jobs',Job :: class,array('label'=>'Job'));;

此操作失败。我的Person类没有职位属性。.那么,如何实现这些目标?我是否必须添加一个带有 tombyBy声明的,具有oneToMany关系的Jobs属性?



这些在学说上的关系仍然让我感到困惑,我是symfony的新人,我看过互联网,但还没有找到合适的解决方案/示例...



感谢阅读/帮助

解决方案

您遇到了一个Symfony形式最困难的问题。幸运的是,这里有一些很好的文档。让我总结一下重要步骤。



您是对的:如果要从Person的角度操纵该实体,那么Person实体需要了解其与PersonJob的关系。视图。因此,您需要添加一个属性:

  // src / AppBundle / Entity / Person.php 
/ **
* @ ORM\OneToMany(targetEntity = PersonJob,mappingBy = person)
* /
private $ personJobs;

公共函数__construct()
{
$ this-> personJobs = new \Doctrine\Common\Collections\ArrayCollection();
}

,然后您将获得表单类型

  // src / AppBundle / Form / PersonType.php 
$ builder
-> add('name')
-> add('firstname')
-> add('personJobs',CollectionType :: class,array(
'entry_type'=> gt; PersonJobType :: class,
' allow_add'=> true,

;

请注意 personJobs 字段。由于一个人可以有很多PersonJobs,因此需要一种可以处理集合的表单类型,这是内置的目的CollectionType (请查看



添加PersonJob:





添加令人讨厌的PersonJob:





收到的数据



提交表单并查看 var_dump 的输出:

  object( AppBundle\Entity\Person)#247(5){
[ id: AppBundle\Entity\Person:private] =>
NULL
[ name: AppBundle\Entity\Person:private] =>
string(12) Charles Dude
[ firstName: AppBundle\Entity\Person:private] =>
string(7) Charles
[ active: AppBundle\Entity\Person:private] =>
bool(true)
[ personJobs: AppBundle\Entity\Person:private] =>
object(Doctrine\Common\Collections\ArrayCollection)#248(1){
[ elements: Doctrine\Common\Collections\ArrayCollection:private] =>
array(2){
[0] =>
object(AppBundle\Entity\PersonJob)#962(6){
[ id: AppBundle\Entity\PersonJob:private] =>
NULL
[ comment: AppBundle\Entity\PersonJob:private] =>
string(19)重要的事情
[ datestart: AppBundle\Entity\PersonJob:private] =>
object(DateTime)#1088(3){…}
[ dateend:…] => …
[ person: AppBundle\Entity\PersonJob:private] =>
NULL
[ job: AppBundle\Entity\PersonJob:private] =>
object(AppBundle\Entity\Job)#1171(2){
[ id: AppBundle\Entity\Job:private] =>
int(2)
[ name: AppBundle\Entity\Job:private] =>
string(5)作业2
}
}
[1] => …
}
}

还有两件事要做:


  1. 设置嵌套的 PersonJob << c $ c> person 属性/ code>实体正确地分配给新的(但尚未持久)的人。


  2. 向学说有关新的 PersonJob 实体,方法是对它们调用 $ em-> persist(...)




相关文档:




Here is the problem :

I have a model with 3 classes

  • person
  • person_job
  • job

A person can have several jobs, any job-person relation can have a "date_start" attribute, "date_end", and "comment". So I built this model with a jointable (person_job) holding these attributes, and making the relationship on 2 manyToOne attributes called person and job (generated with doctrine annotations)

Person attributes looks like :

/**
* @var string
* @ORM\Column(name="name",type="string",length=255,nullable=false)
*/
private $name;

/**
* @var string
* @ORM\Column(name="firstname",type="string",length=255,nullable=true)
*/
private $firstname;
/**
* @var bool
* @ORM\Column(name="active", type="boolean")
*/
private $active;

Job attributes looks like this :

/**
* @var string
* @ORM\Column(name="name",type="string",length=255,nullable=false)
*/
private $name;

person_job looks like this :

/**
* @ORM\ManyToOne(targetEntity="...\Person")
* @ORM\JoinColumn(nullable=false)
*/
private $person;

/**
* @ORM\ManyToOne(targetEntity="...\Job")
* @ORM\JoinColumn(nullable=false)
*/
private $job;

/**
* @var string 
* @ORM\Column(name="comment",type="string",length=255,nullable=true)
*/
private $comment;

/**
* @var \DateTime
* @ORM\Column(name="startdate",type="datetime")
*/
private $datestart;

/**
* @var \DateTime
* @ORM\Column(name="enddate",type="datetime")
*/
private $dateend;

Now I'd like to build a form, for my "person" where I can choose jobs in a list, and add (if needed) date_start, date_end, or comment related to this job. My FormBuilder looks like this for "Person" :

$builder
  ->add('name')
  ->add('firstname')
  ->add('jobs',Job::class,array('label'=>'Job'));

This fails. My Person class has no "jobs" attribute.. So, how can I achieve such things? do I have to add a jobs attribute, with a oneToMany relation on it, declared with "mappedBy"?

These relationships in doctrine still make me confused, I'm new to symfony, I looked on the internet but didn't find a decent solution/example yet...

Thanks for reading/help

解决方案

You have come accross one of the hardest problems with Symfony forms. Fortunately, there is some good documentation. Let me summarize the important steps.

You’re right: The entity Person needs to know about its relationship with PersonJob if you want to manipulate that relationship from a Person’s point of view. So you need to add a property:

// src/AppBundle/Entity/Person.php
/**
 * @ORM\OneToMany(targetEntity="PersonJob", mappedBy="person")
 */
private $personJobs;

public function __construct()
{
    $this->personJobs = new \Doctrine\Common\Collections\ArrayCollection();
}

and then you will have in the form type

// src/AppBundle/Form/PersonType.php
$builder
    ->add('name')
    ->add('firstname')
    ->add('personJobs', CollectionType::class, array(
        'entry_type'   => PersonJobType::class,
        'allow_add' => true,
    )
;

Note the type of the personJobs field. Since a person can have many PersonJobs, you need a form type that can handle collections. This is the purpose of the built-in CollectionType (check out its documentation!). You also need the form type PersonJobType, so that CollectionType knows how to build the sub-forms:

class PersonJobType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('comment')
            ->add('datestart', DateTimeType::class)
            ->add('dateend', DateTimeType::class)
            ->add('job') // requires Job::__toString() to be defined!
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\PersonJob'
        ));
    }
}

For debugging purposes, change your controller to

 public function testAction()
 {
    $person = new Person();
    $form = $this->createForm(PersonType::class, $person);
    $form->add('submit', SubmitType::class);

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        print '<pre>';
        var_dump($form->getData());
        die();
    }

    return $this->render('default/index.html.twig', [
        'form' => $form->createView(),
    ]);
}

Now go ahead and copy & paste the Twig and Javascript code from Adding and Removing Items (you have to make minor changes such as replacing form.emails with form.personJobs).

The form

The form will look like

Just the Person form with a "Add another PersonJob" link:

Adding a PersonJob:

Adding anothing PersonJob:

The data received

Submit the form and see the output of var_dump:

object(AppBundle\Entity\Person)#247 (5) {
  ["id":"AppBundle\Entity\Person":private]=>
  NULL
  ["name":"AppBundle\Entity\Person":private]=>
  string(12) "Charles Dude"
  ["firstName":"AppBundle\Entity\Person":private]=>
  string(7) "Charles"
  ["active":"AppBundle\Entity\Person":private]=>
  bool(true)
  ["personJobs":"AppBundle\Entity\Person":private]=>
  object(Doctrine\Common\Collections\ArrayCollection)#248 (1) {
    ["elements":"Doctrine\Common\Collections\ArrayCollection":private]=>
    array(2) {
      [0]=>
      object(AppBundle\Entity\PersonJob)#962 (6) {
        ["id":"AppBundle\Entity\PersonJob":private]=>
        NULL
        ["comment":"AppBundle\Entity\PersonJob":private]=>
        string(19) "Something important"
        ["datestart":"AppBundle\Entity\PersonJob":private]=> 
        object(DateTime)#1088 (3) { … }
        ["dateend": …] => …
        ["person":"AppBundle\Entity\PersonJob":private]=>
        NULL
        ["job":"AppBundle\Entity\PersonJob":private]=>
        object(AppBundle\Entity\Job)#1171 (2) {
          ["id":"AppBundle\Entity\Job":private]=>
          int(2)
          ["name":"AppBundle\Entity\Job":private]=>
          string(5) "Job 2"
        }
      }
      [1]=> …
  }
}

Two things remain to be done:

  1. Set the person property of the nested PersonJob entities properly to the new (but not yet persisted) Person.

  2. Tell Doctrine about the new PersonJob entities by calling $em->persist(…) on them.

Relevant documentation:

这篇关于一对多的属性,具有Symfony 3 / Doctrine形式的表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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