使用带参数的变量类名创建表单

时间:2017-05-20 15:07:02

标签: php forms symfony oop

我有一个控制器,可以使用变量类名为用户提供正确的表单类型。

有一个名为 EntityForm 的实体,它存储所有可用表单的数据,并提供给出类名和表单类型名称的方法:

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
/**
 * @ORM\Entity
 * @ORM\Table(name="entity_form")
 */
class EntityForm
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @var string
     *
     * @ORM\Column(length=12)
     */
    protected $url;


    /**
     * @var string
     *
     * @ORM\Column
     */
    protected $name;

    /**
     * @var string
     *
     * @ORM\Column(name="class_name")
     */
    protected $className;

    /**
     * @var string
     *
     * @ORM\Column(name="description")
     */
    protected $description;

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

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

        return $this;
    }

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

    /**
     * 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 className
     *
     * @param string $className
     *
     * @return Form
     */
    public function setClassName($className)
    {
        $this->className = $className;

        return $this;
    }

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

    public function createEntity()
    {
        $entity = sprintf('%s\%s', __NAMESPACE__, $this->getClassName());

        return new $entity;
    }

    public function createType()
    {
        return sprintf('AppBundle\Form\%sType', $this->getClassName());
    }
    /**
     * Set description
     *
     * @param string $description
     *
     * @return Form
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

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

创建正确表单的操作修改如下:

/**
 * @Route("/form/ent/{url}", name="entity_form")
 * @Method("GET")
 */
public function formAction(EntityForm $entityForm)
{

    $form = $this->createForm($entityForm->createType())
        ->add('Dodaj!', SubmitType::class, array(
            'attr' => array(
                'class' => 'btn-info'
            )
        ))
    ;

    return $this->render('default/form.html.twig', [
        'form_name' => $entityForm->getName(),
        'form_description' => $entityForm->getDescription(),
        'form' => $form->createView(),
    ]);
}

此控制器链接到正确的表单类型,即。对于 cyclicNewsletter

class CyclicNewsletterType extends AbstractType
{
    private $doctrine;

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

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $currencies = $this->doctrine->getRepository('AppBundle:Currency')->findAll();
        $currenciesFormat = array();

        foreach($currencies as $currency){
            $currenciesFormat += array($currency->getName() .' ('. $currency->getShortName() . ')' => $currency);
        }

        $cycles = $this->doctrine->getRepository('AppBundle:Cycle')->findAll();
        $cyclesFormat = array();

        foreach($cycles as $cycle){
            $cyclesFormat += array($cycle->getName() => $cycle);
        }

        $builder
            ->add('currency', ChoiceType::class, array(
                'label' => 'Waluta',
                'choices' => $currenciesFormat,
            ))
            ->add('cycle', ChoiceType::class, array(
                'label' => 'Cykl',
                'choices' => $cyclesFormat,
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => CyclicNewsletter::class,
        ));
    }
}

现在通过简单的POST操作,我可以轻松地向数据库添加新值,而无需为所有表单编写单独的操作:

/**
 * @Route("/form/ent/{url}", name="form_entity_post")
 * @Method("POST")
 *
 */
public function formPostAction(EntityForm $entityForm, Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $form = $this->createForm($entityForm->createType())
        ->add('Dodaj!', SubmitType::class)
    ;

    $form->handleRequest($request);

    if($form->isSubmitted() && $form->isValid()){
        $formData = $form->getData();


        $formData->setUser($this->container->get('security.token_storage')->getToken()->getUser());
        $em->persist($formData);
        $em->flush();

        return $this->redirectToRoute('form_complete', ['url' => $entityForm->getUrl(), 'entityId' => $formData->getId()]);
    }
    var_dump('problem ' . $form->getErrors());
    exit;
}

然而

我似乎无法使用该方法将已创建的对象注入表单构建器进行编辑。

我的意思是用一个变量类名来创建一个表单创建,它也会存储一个实体实例,这些值已经在表单中设置了。

symfony可以这样吗?

1 个答案:

答案 0 :(得分:1)

您需要将正在编辑的实体的ID添加到您的网址中,并将其设为可选。

* @Route("/form/ent/{url}/{id}", name="form_entity_post",  defaults={"id" = null})

在您的控制器中,在构建表单时,您需要从数据库中获取该对象,并将其作为第二个参数传递给createForm方法。

/**
 * @Route("/form/ent/{url}/{id}", name="form_entity_post",  defaults={"id" = null})
 * @Method("POST")
 *
 */
public function formPostAction(EntityForm $entityForm, Request $request, $id)
{
    $em = $this->getDoctrine()->getManager();

    $entity = null;
    if ($id) {
       $entity = $em->getRepository($entityForm->getClassName)->find($id);
    }

    $form = $this->createForm($entityForm->createType(), $entity)
        ->add('Dodaj!', SubmitType::class)
    ;