使用 Symfony 3 / Doctrine 进行属性形式的一对多对一

2024-05-22

问题是这样的:

我有一个包含 3 个类的模型

  • person
  • 人员_工作
  • job

一个人可以有多个工作,任何工作与人的关系都可以有“date_start”属性、“date_end”和“comment”。因此,我使用持有这些属性的可连接 (person_job) 构建了这个模型,并在称为 person 和 job 的 2 个多对一属性上建立了关系(使用学说注释生成)

人物属性如下:

/**
* @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;

工作属性如下所示:

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

person_job 看起来像这样:

/**
* @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;

现在我想为我的“人”构建一个表单,我可以在列表中选择工作,并添加(如果需要)date_start、date_end 或与此工作相关的评论。对于“Person”,我的 FormBuilder 看起来像这样:

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

这失败了。我的 Person 类没有“jobs”属性。那么,我怎样才能实现这样的目标呢?我是否必须添加一个具有 oneToMany 关系并用“mappedBy”声明的 jobs 属性?

这些教义上的关系仍然让我感到困惑,我是 symfony 的新手,我在互联网上查找,但还没有找到像样的解决方案/示例......

感谢您的阅读/帮助


您遇到了 Symfony 表单最难的问题之一。幸运的是,有一些很好的文档。让我总结一下重要的步骤。

你是对的:如果您想从 Person 的角度操纵该关系,则实体 Person 需要了解其与 PersonJob 的关系。所以你需要添加一个属性:

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

public function __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'   => PersonJobType::class,
        'allow_add' => true,
    )
;

请注意的类型personJobs场地。由于一个人可以拥有多个 PersonJobs,因此您需要一个可以处理集合的表单类型。这就是内置的目的CollectionType(查看它的文档! https://symfony.com/doc/current/reference/forms/types/collection.html)。您还需要表单类型PersonJobType, 以便CollectionType知道如何构建子表单:

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'
        ));
    }
}

出于调试目的,请将控制器更改为

 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(),
    ]);
}

现在继续复制并粘贴 Twig 和 Javascript 代码添加和删​​除项目 https://symfony.com/doc/current/reference/forms/types/collection.html#adding-and-removing-items(您必须进行一些小的更改,例如替换form.emails with form.personJobs).

The form

表格看起来像

只是带有 a 的 Person 表单“添加另一个 PersonJob” link:

添加 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) "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]=> …
  }
}

仍有两件事需要完成:

  1. Set the person嵌套的属性PersonJob实体正确地分配给新的(但尚未持久化的)Person。

  2. 告诉 Doctrine 有关新内容的信息PersonJob通过调用实体$em->persist(…)在他们。

相关文档:

  • 集合类型字段 https://symfony.com/doc/current/reference/forms/types/collection.html
  • 如何嵌入表单集合 https://symfony.com/doc/current/cookbook/form/form_collections.html
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Symfony 3 / Doctrine 进行属性形式的一对多对一 的相关文章