使用单表继承构建表单

2022-01-03 00:00:00 orm php symfony doctrine-orm

我有我的实体文章和一个像这样的单表继承:

/*** 文章** @ORMTable(name="文章")* @ORMEntity(repositoryClass="PMPlatformBundleRepositoryArticleRepository")* @ORMInheritanceType("SINGLE_TABLE")* @ORMDiscriminatorColumn(name="media", type="string")* @ORMDiscriminatorMap({"article" = "Article", "movie" = "Movie", "image" = "Image", "text" = "Text"})*/类文章{受保护的 $id;受保护的 $title;受保护的 $ 说明;受保护的 $author;//其他属性和setter getter}类图像扩展文章{私人 $path;//getter setter}类电影扩展文章{私人 $url;//getter setter}

所以我的文章的对象类型是图像或电影或仅文本.好的,现在我想构建一个表单,用户可以在其中发布新文章:在这种表单中,用户必须在树类型(3 个单选按钮):图像或电影或文本之间进行选择,当然还有其他字段:标题和描述.我怎么能这样做?因为用命令

<块引用>

php bin/console 原则:generate:form myBundle:Article

呈现的表单是:

class ArticleType 扩展 AbstractType{/*** @param FormBuilderInterface $builder* @param 数组 $options*/公共函数 buildForm(FormBuilderInterface $builder, array $options){$builder->add('title', TextType::class)->add('description', TextareaType::class)->add('save', SubmitType::class);;}/*** @param OptionsResolver $resolver*/公共函数 configureOptions(OptionsResolver $resolver){$resolver->setDefaults(array('data_class' =>'PMPlatformBundleEntityArticle'));}}

我不知道如何以这种形式实现我的 STI 关系.因为我的文章实体/对象中没有该类型的字段(仅在我的表中).我必须添加一个 Custom ChoiceType() 字段,但它需要一个属性.当我尝试在表单中添加它时:

<块引用>

 ->add('path', SearchType::class)->add('url', UrlType::class)

我收到此错误:

属性path"和方法getPath()"、path()"、isPath()"、hasPath()"、__get()"都不存在并且在类中具有公共访问权限PMPlatformBundleEntityArticle".

因为我创建了一个文章的实例,而不是一个图像或电影的实例.最初我创建了一个 STI,认为一个新的文章实例也允许我定义文章的类型".但不是 ?对吗?

解决方案

你必须制作三种形式(一种用于Article,一种用于Movie,一种用于对于 Image).然后,在您的控制器中,您必须选择处理它们:

  • 您可以使用一个操作来处​​理这三个表单(您可以使用 $form->isSubmitted() 检查哪个提交了)
  • 您按表单创建一个操作,然后设置表单操作 URL将每个表单发送到正确的控制器.

最后,在您的模板中,您将表单封装在一个 div 中,并使用我上一篇文章中的示例.

{% 扩展 "CoreBundle::layout.html.twig" %}{% 区块标题 %}{{ parent() }}{% endblock %}{% 阻止 btn_scrollspy %}{% 结束块 %}{% 块 bundle_body %}<div class="well"><div class="选择器"><input type="radio" name="form-selector" value="article-form">文章<input type="radio" name="form-selector" value="movie-form">电影<input type="radio" name="form-selector" value="image-form">图片

<div class="form article-form" style="display: none;">{{ 表单(文章表单)}}

<div class="form movie-form" style="display: none;">{{ 形式(电影形式)}}

<div class="form image-form" style="display: none;">{{ 表单(图像表单)}}

{% 结束块 %}

I have my entity Article and one single table inheritance like this :

/**
 * Article
 *
 * @ORMTable(name="article")
 * @ORMEntity(repositoryClass="PMPlatformBundleRepositoryArticleRepository")
 * @ORMInheritanceType("SINGLE_TABLE")
 * @ORMDiscriminatorColumn(name="media", type="string")
 * @ORMDiscriminatorMap({"article" = "Article", "movie" = "Movie", "image" = "Image", "text" = "Text"})
 */
class Article
{
    protected $id;
    protected $title;
    protected $description;
    protected $author;
    //other attributes and setters getters
}

class Image extends Article
{
    private $path;
    //getter setter
}

 class Movie extends Article
{
    private $url;
    //getter setter
}

So my article's object type is either Image or movie or text only. Ok now I would like build a form wherein users can post a new article : in this form, the user has to choice between tree type (3 radios button) : image OR movie OR text only and of course the other fields : title and description. How I can do that ? Because with the command

php bin/console doctrine:generate:form myBundle:Article

The form rendered is :

class ArticleType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title',          TextType::class)
            ->add('description',    TextareaType::class)
            ->add('save',           SubmitType::class);
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'PMPlatformBundleEntityArticle'
        ));
    }
}

I don't know the way to implement my STI relation in this form. Because I have not field in my Article entity/object for the type (only in my table). I have to add a Custom ChoiceType() field but it require a attribute. When I try to add this in the form :

        ->add('path',           SearchType::class)
        ->add('url',            UrlType::class)

I got this error :

Neither the property "path" nor one of the methods "getPath()", "path()", "isPath()", "hasPath()", "__get()" exist and have public access in class "PMPlatformBundleEntityArticle".

Because I have create an instance of Article, not an instance of Image or Movie. Initially I created a STI thinking a new instance of Article would allow me also to define the "type" of article. But not ? Right ?

解决方案

You will have to make three forms (one for an Article, one for a Movie and one for an Image). Then, in your controller, you have to options to deal with them:

  • Either you use one action to handle the three forms (you can check wich one is submitted by using $form->isSubmitted())
  • You create one action by form, and set the form action URL for each form to the correct controller.

Finally, in your template, you encapsulate your forms in a div, and use the example in my previous post.

{% extends "CoreBundle::layout.html.twig" %}

{% block title %}{{ parent() }}{% endblock %}

{% block btn_scrollspy %}
{% endblock %}


{% block bundle_body %}
    <div class="well">
        <div class="selector">
            <input type="radio" name="form-selector" value="article-form"> Article
            <input type="radio" name="form-selector" value="movie-form"> Movie
            <input type="radio" name="form-selector" value="image-form"> Image
        </div>

        <div class="form article-form" style="display: none;">
            {{ form(articleForm) }}
        </div>
        <div class="form movie-form" style="display: none;">
            {{ form(movieForm) }}
        </div>
        <div class="form image-form" style="display: none;">
            {{ form(imageForm) }}
        </div>
    </div>
{% endblock %}

相关文章