如何嵌套 Symfony 表单 类?
How to nest Symfony form classes?
我在弄清楚如何为我拥有的三个实体创建嵌套表单的逻辑时遇到问题:Films、Actors 和地点。我按照 symfony 文档 here.
中的说明从我的数据库生成了我的 Symfony 实体 (+orm.xml
)
我的最终目标是拥有一个页面,用户可以在其中执行以下任何操作:
- 创建一个新的电影对象
- Select Films,然后创建一个新的 Actors 对象与之关联
- Select Films,然后创建一个新的 Locations 对象与之关联
(Actors 和 Locations 都具有与 Films
table 的一对多连接)
但是,我一直在为 Symfony 中嵌套表单的概念苦苦挣扎很长时间,为了 "walk before I can run" 我只是想把以上每一项都以不同的形式分成不同的路线:
/newfilm
/newactor
/newlocation
/New-film
我可以毫无问题地工作。然而,对于其他两个,我尝试的任何事情似乎都不起作用。下面是我的代码,如果有人能解释一下 Symfony 中嵌套表单的 "theory" 以避免不断撞墙,将不胜感激...!
因为我的问题对于 Actor 和 Location 都是一样的,所以我只为 Actors(和 Films ) 因为我意识到它已经很多了:
~~~~~控制器~~~~~
这是第二条路线 (/newactor
) 具有 embedded/nested 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';
}
}
我当前的错误信息是:
Catchable Fatal Error: Object of class AppBundle\Entity\Films could not be converted to string
500 Internal Server Error - ContextErrorException
我已经阅读了关于将函数添加到我的 Films.php
:
的答案
public function __toString() {
return $this->name;
}
但是,当我这样做时,我得到了错误:
Error: Method AppBundle\Entity\Films::__toString() must not throw an exception
我在网上遇到的其他可能的想法(但不幸的是没有成功)是:
- 将表单设置为服务
- 数据转换器
将 'choice_label' => 'film_title',
添加到您的表单生成器。或者你可以在你的电影实体中实现一个 __toString()
函数,returns 电影标题。
解法:
$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-to-many 实体关系时,这可能会导致不必要的问题。
我在弄清楚如何为我拥有的三个实体创建嵌套表单的逻辑时遇到问题:Films、Actors 和地点。我按照 symfony 文档 here.
中的说明从我的数据库生成了我的 Symfony 实体 (+orm.xml
)
我的最终目标是拥有一个页面,用户可以在其中执行以下任何操作:
- 创建一个新的电影对象
- Select Films,然后创建一个新的 Actors 对象与之关联
- Select Films,然后创建一个新的 Locations 对象与之关联
(Actors 和 Locations 都具有与 Films
table 的一对多连接)
但是,我一直在为 Symfony 中嵌套表单的概念苦苦挣扎很长时间,为了 "walk before I can run" 我只是想把以上每一项都以不同的形式分成不同的路线:
/newfilm
/newactor
/newlocation
/New-film
我可以毫无问题地工作。然而,对于其他两个,我尝试的任何事情似乎都不起作用。下面是我的代码,如果有人能解释一下 Symfony 中嵌套表单的 "theory" 以避免不断撞墙,将不胜感激...!
因为我的问题对于 Actor 和 Location 都是一样的,所以我只为 Actors(和 Films ) 因为我意识到它已经很多了:
~~~~~控制器~~~~~
这是第二条路线 (/newactor
) 具有 embedded/nested 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';
}
}
我当前的错误信息是:
Catchable Fatal Error: Object of class AppBundle\Entity\Films could not be converted to string
500 Internal Server Error - ContextErrorException
我已经阅读了关于将函数添加到我的 Films.php
:
public function __toString() {
return $this->name;
}
但是,当我这样做时,我得到了错误:
Error: Method AppBundle\Entity\Films::__toString() must not throw an exception
我在网上遇到的其他可能的想法(但不幸的是没有成功)是:
- 将表单设置为服务
- 数据转换器
将 'choice_label' => 'film_title',
添加到您的表单生成器。或者你可以在你的电影实体中实现一个 __toString()
函数,returns 电影标题。
解法:
$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-to-many 实体关系时,这可能会导致不必要的问题。