2

Symfony 2.2 と Doctrine を使用してフォーム ジェネレーターを構築しています。基本原則は、ユーザーが名前を入力し、選択メニューで使用したいウィジェットを選択して、新しいフォームを作成することです。

WidgetInputText、WidgetSelect、WidgetFile などが考えられます。

これが私のモデルの例です:

<?php

namespace Ineat\FormGeneratorBundle\Entity\Widget;
use Symfony\Component\Validator\Constraints as Assert;


use Doctrine\ORM\Mapping as ORM;

/**
 * Widget
 *
 * @ORM\Table(name="widget")
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="discr", type="string")
 * @ORM\DiscriminatorMap({"widget_text" = "WidgetText", "widget_input_text" = "WidgetInputText", "widget_select" = "WidgetSelect"})
 */
abstract class Widget
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Form", inversedBy="widgets")
     */
    private $form;

    /**
     * @var integer
     *
     * @ORM\OneToOne(targetEntity="Question")
     */
    private $question;

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set form
     *
     * @param \Ineat\FormGeneratorBundle\Entity\Form $form
     * @return Widget
     */
    public function setForm(\Ineat\FormGeneratorBundle\Entity\Form $form = null)
    {
        $this->form = $form;

        return $this;
    }

    /**
     * Get form
     *
     * @return \Ineat\FormGeneratorBundle\Entity\Form 
     */
    public function getForm()
    {
        return $this->form;
    }

    /**
     * Set question
     *
     * @param \Ineat\FormGeneratorBundle\Entity\Question $question
     * @return Widget
     */
    public function setQuestion(\Ineat\FormGeneratorBundle\Entity\Question $question = null)
    {
        $this->question = $question;

        return $this;
    }

    /**
     * Get question
     *
     * @return \Ineat\FormGeneratorBundle\Entity\Question 
     */
    public function getQuestion()
    {
        return $this->question;
    }
}

<?php

namespace Ineat\FormGeneratorBundle\Entity\Widget;

use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;

/**
 * Widget
 *
 * @ORM\Entity
 * @ORM\Table(name="widget_text")
 */
class WidgetText extends Widget
{
    /**
     * @var string
     *
     * @ORM\Column(type="text")
     */
    private $text;

    /**
     * Set text
     *
     * @param string $text
     * @return WidgetText
     */
    public function setText($text)
    {
        $this->text = $text;

        return $this;
    }

    /**
     * Get text
     *
     * @return string 
     */
    public function getText()
    {
        return $this->text;
    }
}

<?php

namespace Ineat\FormGeneratorBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Form
 *
 * @ORM\Table(name="form")
 * @ORM\Entity(repositoryClass="Ineat\FormGeneratorBundle\Entity\FormRepository")
 * @UniqueEntity("name")
 * @UniqueEntity("slug")
 */
class Form
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

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

    /**
     * @var ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="Widget", mappedBy="form", cascade={"persist"})
     */
    private $widgets;


    public function __construct()
    {
        $this->widgets = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Form
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set slug
     *
     * @param string $slug
     * @return Form
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;

        return $this;
    }

    /**
     * Get slug
     *
     * @return string 
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Add widgets
     *
     * @param \Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget
     * @return Form
     */
    public function addWidget(\Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget)
    {
        $this->widgets[] = $widget;

        return $this;
    }

    /**
     * Remove widgets
     *
     * @param \Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget
     */
    public function removeWidget(\Ineat\FormGeneratorBundle\Entity\Widget\Widget $widget)
    {
        $this->widgets->removeElement($widget);
    }

    /**
     * Get widgets
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getWidgets()
    {
        return $this->widgets;
    }

    /**
     * Set widgets
     *
     * @param \Doctrine\Common\Collections\Collection $widgets
     */
    public function setWidget(\Doctrine\Common\Collections\Collection $widgets)
    {
        $this->widgets = $widgets;
    }

    public function __set($name, $obj)
    {
        if (is_a($obj, '\Ineat\FormGeneratorBundle\Entity\Widget\Widget')) {
            $this->addWidget($obj);
        }
    }
}

ご覧のとおり、フォームには複数のウィジェットを関連付けることができます。

すべてのウィジェットに共通のフィールドがあり、Widget 型であるため、抽象クラス Widget を作成しました。また、Form エンティティでは、Widget 型ごとに 1 つのコレクションを持つのは非常に悪いように思われるため (悪くて退屈です)。

このモデルは機能し、単体テストを行い、WidgetText をフォームに添付して取得することができました。

問題は、フォームを使用しようとしたときに発生します。

<?php

namespace Ineat\FormGeneratorBundle\Form;

use Ineat\FormGeneratorBundle\Entity\Widget\WidgetText;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class FormType extends AbstractType
{
    protected $widgets;

    public function __construct(array $widgets = array())
    {
        $this->widgets = $widgets;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', 'text')
            ->add('slug', 'text')
            ->add('WidgetText', 'collection', array(
                'type'         => new WidgetTextType(),
                'allow_add'    => true,
                'attr'         => array('class' => 'widget-text'),
                'by_reference' => false
            ))
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Ineat\FormGeneratorBundle\Entity\Form',
        ));
    }

    public function getName()
    {
        return 'ineat_formgeneratorbundle_formtype';
    }
}

<?php

namespace Ineat\FormGeneratorBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class WidgetTextType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('text', 'text')
        ;
    }

    public function getName()
    {
        return 'ineat_formgeneratorbundle_widgettexttype';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Ineat\FormGeneratorBundle\Entity\Widget\WidgetText',
        ));
    }
}

フォームを表示しようとすると、次のエラーが発生します。

クラス「Ineat\FormGeneratorBundle\Entity\Form」には、プロパティ「WidgetText」もメソッド「getWidgetText()」もメソッド「isWidgetText()」も存在しません。

私の WidgetText も Widget 型であることを Symfony が認識していないようです。

コントローラー (Symfony によって生成された) の場合、次の行を変更します。

$this->createForm(new FormType(), new Form())

に:

$this->createForm(new FormType())

フォームはうまく表示されますが、送信時にデータがバインドされていません。

OOP の観点からは、これでうまくいくと思いますが、Symfony で自分のやりたいことができるかどうかはわかりません。

4

1 に答える 1

0

質問のコメントで述べたように、「WidgetText」フィールドの名前を「widgets」に変更する必要があります。その背後にある理由は、フィールドの名前がモデルのアクセサーと一致する必要があるためです (つまり、 の「名前」(set|get)Name()、「ウィジェット」(set|get)Widgets()など)。

フィールドの名前をモデルのアクセサーとは異なるものにしたい場合は、"property_path" オプション (デフォルトでフィールドの名前に設定されています) を使用することもできます。

$builder->add('WidgetText', ..., array(
    ...
    'property_path' => 'widgets',
));
于 2013-08-20T08:38:18.250 に答える