Symfony 2.8+,教义继承与形式 [英] Symfony 2.8+, Doctrine Inheritance and Forms

查看:108
本文介绍了Symfony 2.8+,教义继承与形式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我开始之前,请注意,我正在学习symfony,以便牢记这一点!我只是想了解它是如何工作的。
这是我想要实现的:



我想用一个使用原则的实体继承的工作粗暴的例子。所以这就是我的例子:




  • 抽象家长班:角色

  • 小孩类1:魔术师

  • 小孩类2:战士

  • 孩子类3:弓箭手



所以在阅读了一些文档后,我决定使用STI(单表继承)的原则。



父类:

  / ** 
*字符
*
* @ ORM\Table(name =character)
* @ ORM\Entity(repositoryClass =AppBundle\\
* @ ORM\InheritanceType(SINGLE_TABLE)
* @ ORM\DiscriminatorColumn(name =discr,type =string)
* @ ORM\DiscriminatorMap({magician_db=Magician,warrior_db=Warrior,archer_db=Archer})
* /

抽象类Character {
protected id;
保护名称;
public function getId();
public function getName();
public function setName();
}

小孩类1:

  class Warrior extends Character {
protected armor;
public function battleShout();
}

小孩类2:

  class Magician extends Character {
protected silk;
public function spellAnnounce();
}

子类3:

  class Archer extends Character {
protected leather;
public function arrows();
}

我设法在我的数据库中创建表,我成功加载了我的装置用于测试目的。我也使我的主要工作(列出所有字符)。






我的问题:
现在我想要创建,编辑和使用单个表单删除列表中的特定字符。所以例如我会有一个'type'选择字段,我可以选择'warrior','magician'或'archer',然后我可以填写所选实体的特定字段。所以让我们选择'warrior'的形式,然后我想要设置装甲属性(和父母一起当然),并将其保存在数据库中。



我不知道如何做,因为我的父类是抽象的,所以我不能创建一个基于该对象的表单。



Thx提前为您的帮助,我真的需要它!



PS:如果有更好的解决方案/实施不要犹豫!

解决方案

最简单的方法是提供所有字段,并根据'type'值删除它们。 / p>

为此,您必须在客户端(用于显示目的)和服务器端实现逻辑(以便您的实体中不能更改已删除的字段)。 / p>

在客户端:




  • 使用javascript隐藏不能为每个类型更改设置的类型(可以)使用JQuery和.hide()函数)。



在服务器端:




  • 将PRE_BIND事件添加到表单类型,以从表单中删除字段:



http://symfony.com/doc/current/components/form/form_events.html#a-the-formevents-pre-submit-event



您的表单应如下所示:

  // ... 

使用Symfony\Component \Form\FormEvent;
使用Symfony\Component\Form\FormEvents;
用Symfony\Component\Form\Extension\Core\Type\ChoiceType;

$ form = $ formFactory-> createBuilder()
- > add('type',ChoiceType :: class)
- > add('armor'
- > add('silk')
- > add('leather')
- > addEventListener(FormEvents :: PRE_SUBMIT,function(FormEvent $ event){
$ submittedData = $ event-> getData();
$ form = $ event-> getForm();

switch($ submittedData ['type'])
{
case'warrior':
$ form-> remove('silk');
$ form-> remove('leather');
break;
case'magician':
$ form-> remove('armor');
$ form-> remove('leather');
break;
case'archer':
$ form-> remove('armor');
$ form-> remove('silk');
break;
default:
throw new ...;
}
})
- > getForm();

// ...

编辑



要处理单表继承,您不能使用抽象类,基类必须是正常实体。



在您的表单中,只需将类设置为 AppBundle\Character



在创建字符的控制器操作中,您必须以下列方式启动您的实体:

  if($ request-> isMethod('POST')){
// form已经提交
switch($ request-> get('type'))
{
case'warrior':
$ entity = new Warrior ();
...
}
}
else {
//表单尚未提交,默认值:Warrior
$ entity = new Warrior();
}

通过编辑和删除字符,您可以直接处理字符实体。



我建议不要让用户通过编辑更改类型,请参阅 Doctrine:更新SINGLE_TABLE继承的鉴别器


Before i start, Note that I'm learning symfony so keep that in mind ! I just want to understand how it works. Here's what i am trying to achieve :

I would like to make a working crud example of entities inheritance using doctrine. So this is how my example looks like :

  • Abstract Parent class : character
  • Child class 1 : Magician
  • Child class 2 : Warrior
  • Child class 3 : Archer

So after reading some documentation i decided to use the STI (Single Table Inheritance) of Doctrine.

Parent class :

/**
 * Character
 *
 * @ORM\Table(name="character")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CharacterRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"magician_db" = "Magician", "warrior_db" = "Warrior", "archer_db" = "Archer"})
 */

abstract class Character{
    protected id;
    protected name;
    public function getId();
    public function getName();
    public function setName();
}

Child Class 1 :

class Warrior extends Character{
       protected armor;
       public function battleShout();
}

Child Class 2:

class Magician extends Character{
       protected silk;
       public function spellAnnounce();
}

Child Class 3:

class Archer extends Character{
       protected leather;
       public function arrows();
}

I managed to create the table in my db, and i successfully loaded my fixtures for tests purposes. I also made my main view work (listing all characters).


My Problem : Now i want to be able to create, edit & delete a specific character in the list with a single form. So for example i would have a 'type' select field where i can select 'warrior' , 'magician' or 'archer' and then i would be able to fill in the specific fields of the chosen entity. So let's say i choose 'warrior' in the form, then i would like to be able to set the armor property (along with the parents one of course) and persist it in the database.

I don't know how to do it since my parent class is abstract so i can't create a form based on that object.

Thx in advance for your help, i really need it !

PS: If there is a better solution / implementation don't hesitate !

解决方案

The easiest way is to provide all fields and to remove them according to the 'type' value.

To do that you have to implement the logic on the client side (for displaying purpose) and server side (so that the removed fields cannot be changed in your entity).

On the client side :

  • Use javascript to hide the types which can't be set for each 'type' change (you can use JQuery and the .hide() function).

On the server side:

  • Add a PRE_BIND event to your form type, to remove the fields from the form :

http://symfony.com/doc/current/components/form/form_events.html#a-the-formevents-pre-submit-event

Your Form should look like :

// ...

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

$form = $formFactory->createBuilder()
    ->add('type', ChoiceType::class)
    ->add('armor')
    ->add('silk')
    ->add('leather')
    ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
        $submittedData = $event->getData();
        $form = $event->getForm();

        switch($submittedData['type'])
        {
            case 'warrior':
                $form->remove('silk');
                $form->remove('leather');
            break;
            case 'magician':
                $form->remove('armor');
                $form->remove('leather');
            break;
            case 'archer':
                $form->remove('armor');
                $form->remove('silk');
            break;
            default:
            throw new ...;
        }
    })
    ->getForm();

// ...

EDIT

To deal with Single Table Inheritance, you can't use an abstract class, the base class must be a normal entity.

In your form, just set the class as AppBundle\Character.

In your controller action which creates the character, you must initiate your entity with something like this :

if($request->isMethod('POST')){
    // form has been submitted
    switch($request->get('type'))
    {
        case 'warrior':
        $entity = new Warrior();
        ...
    }
}
else{
    // form has not been submitted, default : Warrior
    $entity = new Warrior();
}

By editing and removing the character, you can directly deal with the Character Entity.

I recommand to not let the user change the type by edit, see Doctrine: Update discriminator for SINGLE_TABLE Inheritance

这篇关于Symfony 2.8+,教义继承与形式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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