【问题标题】:How to nest Symfony form classes?如何嵌套 Symfony 表单类?
【发布时间】:2015-11-14 22:21:38
【问题描述】:

我在弄清楚如何为我拥有的三个实体创建嵌套表单的逻辑时遇到问题:FilmsActorsLocations .我按照 symfony 文档 here 中的说明从我的数据库中生成了我的 Symfony 实体 (+orm.xml)。

我的最终目标是拥有一个用户可以执行以下任何操作的页面:

  • 创建一个新的电影对象
  • 从下拉菜单中选择 Films,然后创建一个新的 Actors 对象与之关联
  • 从下拉菜单中选择电影,然后创建一个新的Locations对象与之关联

ActorsLocations 都具有与Films 表的一对多联接)

然而,我一直在为 Symfony 中嵌套表单的概念苦苦挣扎,为了“在我能跑之前先走”,我只是想把每个上面分成不同形式的不同路线:

  • /newfilm
  • /newactor
  • /newlocation

/New-film我可以毫无问题地开始工作。但是,对于其他两个中的任何一个,我尝试的任何方法似乎都不起作用。以下是我的代码,如果有人能解释 Symfony 中嵌套形式的“理论”以避免继续撞到这堵墙,将不胜感激......!

由于我的问题对于 Actor 和 Location 都是一样的,所以我只为 Actors(和 Films)添加代码,因为我意识到它很多已经:

~~~~~控制器~~~~~

第二条路线 (/newactor) 具有嵌入/嵌套的 formType:

class DefaultController extends FOSRestController
{
    /**
     * @Route("/newfilm", name="new_film")
     */
    public function newFilmAction(Request $request)
    {
        $film = new Films();
        $form = $this->CreateFormBuilder($film)
            ->add('film_title','text',array('label'=>'Film title'))
            ->add('Save','submit',array('label'=>'Add new film'))
            ->getForm();
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($film);
            $em->flush();
            return $this->redirectToRoute('success_addFilm');
        }

        return $this->render('AppBundle:Default:newfilm.form.html.twig', array(
            'form' => $form->createView(),
        ));
    }


    /**
     * @Route("/newactor", name="new_actor")
     */
    public function newActorAction(Request $request)
    {
        $actor = new Actors();
        $form = $this->createForm(new ActorType(), $actor);
        $form->handleRequest($request);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($actor);
            $em->flush();
            return $this->redirectToRoute('success_addActor');
        }

        return $this->render('AppBundle:Default:newactor.form.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

~~~~~电影~~~~~

Films.php

/**
 * Films
 */
class Films
{
    /**
     * @var integer
     */
    private $filmid;

    /**
     * @var string
     */
    private $film_title;

    /**
     * @var \AppBundle\Entity\Actors
     */
    private $actor;



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

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

    /**
     * Set film_title
     * @param string $film_title
     * @return Films
     */
    public function setFilm_title($film_title)
    {
        $this->film_title = $film_title;
        return $this;
    }

    /**
     * Set actor
     *
     * @param \AppBundle\Entity\Actors $actor
     *
     * @return Actors
     */
    public function setActor(\AppBundle\Entity\Actors $actor = null)
    {
        $this->actor = $actor;

        return $this;
    }

    /**
     * Get actor
     *
     * @return \AppBundle\Entity\Actors
     */
    public function getActor()
    {
        return $this->actor;
    }
}

Films.orm.xml

<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
  <entity name="AppBundle\Entity\Films" table="Films">
    <indexes>
      <index name="fk_Films_actors1_idx" columns="actor_id"/>
    </indexes>
    <id name="filmid" type="integer" column="filmid">
      <generator strategy="IDENTITY"/>
    </id>
    <field name="film_title" type="text" column="film_title" length="65535" nullable="false">
      <options>
        <option name="fixed"/>
      </options>
    </field>
    <many-to-one field="actor" target-entity="Actors" fetch="LAZY">
      <join-columns>
        <join-column name="actor_id" referenced-column-name="actorid"/>
      </join-columns>
    </many-to-one>
  </entity>
</doctrine-mapping>

FilmType.php

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

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'=>'AppBundle\Entity\Films'
        ));
    }

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

~~~~~演员~~~~~

Actors.php

/**
 * Entries
 */
class Entries
{
    /**
     * @var integer
     */
    private $actorid;


    /**
     * @var string
     */
    private $actorName;




    /**
     * Set actorid
     *
     * @param integer $actorid
     *
     * @return Actors
     */
    public function setActorid($actorid)
    {
        $this->actorid = $actorid;

        return $this;
    }

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

    /**
     * Set actorName
     *
     * @param string $actorName
     *
     * @return Actors
     */
    public function setActorName($actorName)
    {
        $this->actorName = $actorName;

        return $this;
    }

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

Actors.orm.xml

<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
  <entity name="AppBundle\Entity\Actors" table="Actors">
    <id name="actorid" type="integer" column="actorid">
      <generator strategy="IDENTITY"/>
    </id>
    <field name="actorName" type="text" column="actorName" length="65535" nullable="true">
      <options>
        <option name="fixed"/>
      </options>
    </field>
  </entity>
</doctrine-mapping>

演员类型

class ActorType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('actorName')
            ->add('film','entity',array(
              'class'=>'AppBundle:Films',
                'query_builder'=>function(EntityRepository $er) {
                    return $er->createQueryBuilder('f')
                        ->orderBy('f.film_title','ASC');
                }
            ));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'=>'\AppBundle\Entity\Actors'
        ));
    }

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

我当前的错误信息是:

可捕获的致命错误:AppBundle\Entity\Films 类的对象无法转换为字符串

500 内部服务器错误 - ContextErrorException

我已经阅读了将函数添加到我的Films.php 的答案:

public function __toString() {
    return $this->name;
}

但是,当我这样做时,我得到了错误:

错误:方法 AppBundle\Entity\Films::__toString() 不得抛出异常

我在网上遇到的其他可能的想法(但不幸的是没有成功)是:

  • 将表单设置为服务
  • 数据转换器

【问题讨论】:

  • 为什么是 xml? yaml 更具可读性
  • 感谢您的关注 :) 我一直在尝试使用“最佳实践”并阅读了这篇文章,该文章建议使用 XML,以便将捆绑包解耦以跨项目使用....否则我同意我d 不会因为注释而感到头疼......! blog.danielribeiro.org/…
  • @Bendy 那篇文章已经过时了。如果您想要“最佳实践”,您应该使用注释。 symfony.com/doc/current/best_practices/…
  • 非常感谢您的链接 - 尽管对于解耦捆绑包,将数据库映射放在单独的文件中而不是与实体 php 文件交错似乎是有意义的...?
  • 在配置文件中使用yaml,在实体和控制器类中尽量使用注解

标签: forms symfony doctrine entity


【解决方案1】:

'choice_label' =&gt; 'film_title', 添加到您的表单构建器。或者您可以在您的 Film 实体中实现一个 __toString() 函数,该函数返回电影标题。

解决方案:

$builder
    ->add('actorName')
    ->add('film','entity',array(
        'class'=>'AppBundle:Films',
        'choice_label'  =>  'film_title',
        'query_builder'=>function(EntityRepository $er) {
            return $er->createQueryBuilder('f')
                ->orderBy('f.film_title','ASC');
        }
    ));

此外,您可能希望实体名称保持单数(例如:Film,而不是 Films;Actor 不是 Actors),因为这可能会在处理 x 对多实体关系时导致不必要的问题。

【讨论】:

  • choice_label 已修复,谢谢!您关于保持实体名称单一的评论 - 我也想知道这一点。但是,数据库表的“最佳实践”是让表以复数形式命名以包含什么内容?
  • 你可以给你的实体一个单数的名字,但你的表格可以用另一个名字,例如@ORM\Table(name="products") 你的类名应该是 Product。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-01
  • 2016-12-08
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
相关资源
最近更新 更多