Symfony2 Entity Form Type 获取数据
Symfony2 Entity Form Type gets data
我有 2 个实体:音频和目标
音频中:
/**
* @ORM\OneToOne(targetEntity="HearWeGo\HearWeGoBundle\Entity\Destination", inversedBy="audio")
* @Assert\NotBlank(message="This field must be filled")
*
*/
private $destination;
我创建了一个名为 AddAudioType 的表单类型,用于将音频上传到数据库
<?php
namespace HearWeGo\HearWeGoBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use HearWeGo\HearWeGoBundle\Entity\Audio;
class AddAudioType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name','text')
->add('content','file')
->add('destination','entity',array('class'=>'HearWeGoHearWeGoBundle:Destination','property'=>'name'))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array('data_class'=>"HearWeGo\HearWeGoBundle\Entity\Audio"));
}
public function getName()
{
return 'add_audio';
}
}
?>
在控制器中
/**
* @Route("/admin/add/audio",name="add_audio")
*/
public function addAudioAction(Request $request)
{
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')){
return new Response('Please login');
}
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
$audio=new Audio();
$form=$this->createForm(new AddAudioType(),$audio,array(
'method'=>'POST',
'action'=>$this->generateUrl('add_audio')
));
$form->add('submit','submit');
if ($request->getMethod()=='POST')
{
$form->handleRequest($request);
if ($form->isValid())
{
$destination=$this->getDoctrine()->getRepository('HearWeGoHearWeGoBundle:Destination')
->findByName($form->get('destination')->getData()->getName());
$audio->setDestination($destination);
$name=$_FILES['add_audio']['name']['content'];
$tmp_name=$_FILES['add_audio']['tmp_name']['content'];
if (isset($name))
{
if (!empty($name))
{
$location=$_SERVER['DOCUMENT_ROOT']."/bundles/hearwegohearwego/uploads/";
move_uploaded_file($tmp_name,$location.$name);
$audio->setContent($location.$name);
$em=$this->getDoctrine()->getEntityManager();
$em->persist($audio);
$em->flush();
return new Response('Audio '.$audio->getName().' has been created!');
}
}
}
}
return $this->render('@HearWeGoHearWeGo/manage/addAudio.html.twig',array('form'=>$form->createView()));
}
在 AddAudioType 中,我声明它从目标实体 table 获取所有记录并允许用户选择其中之一,然后将其保存到数据库
现在还有一件事我必须处理:因为 Audio 和 Destination 之间的关系是一对一的,所以不允许用户选择已经出现在 Audio 中的 Destination table。现在在 AddAudioType 中,我不想从 Destination table 获取所有记录,而只是想获取尚未出现在 Audio table 中的一些记录。我应该怎么做?
当您在表单生成器中执行操作时
->add('destination', 'entity', array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'property'=>'name'
));
你是说你想要所有可能的 Destination
个实体
如果要过滤,有两种可能
第一个(推荐)
编写您自己的方法,将已经“关联”的 Destinations
排除到 DestionationRepository
中。如果您不知道什么是存储库或者不知道如何编写存储库,请参阅此document。方法实现留给你作为练习(不,真的,我不了解所有实体,所以我无法做出任何猜测)
完成此操作后,您必须将 DestinationRepository
作为选项传递给您的表单( 需要 我想 [参见 setRequired()
方法下面]),所以,像这样(我将省略无趣的代码)
//AddAudioType
<?php
[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
$destination_repo = $options['dr'];
$builder->[...]
->add('destination','entity',array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'choices'=> $destination_repo->yourCustomRepoFunctionName(),
'property'=>'name'));
}
$resolver->setRequired(array(
'dr',
));
现在您已经为您的表单设置了所有内容,您需要将 DestinationRepository
传递给您的表单。你怎么做到的?
确实很简单
//In controller you're instatiating your form
[...]
public function addAudioAction()
{
[...]
$destination_repo = $this->getDoctrine()
->getManager()
->getRepository('HearWeGoHearWeGoBundle:Destination');
$form=$this->createForm(new AddAudioType(), $audio, array(
'method' => 'POST',
'action' => $this->generateUrl('add_audio'),
'dr' => $destination_repo,
));
}
只要你写了一个好的“过滤器”方法(即:你用 NOT IN
子句排除了所有 Destinations
,它得到了其他 table)
第二个
您只需将您的方法写入表单
//AddAudioType
use Doctrine\ORM\EntityRepository;
<?php
[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
$destination_repo = $options['dr'];
$builder->[...]
->add('destination','entity',array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'choices'=> function(EntityRepository $repository) use ($someParametersIfNeeded) {
return $repository->createQueryBuilder('d')
->[...];},
'property'=>'name'));
}
在第二种情况下,createQueryBuilder
也没有实现,留给你。您需要记住一件事:choices
将需要一个查询构建器,所以不要调用 ->getQuery()
和 ->getResult()
为什么是拳头?
- 自定义函数应始终保留在存储库中。因此,您正在将一些代码写入必须的位置(请参阅下面的要点以了解方式)
- 因为这样的代码是可重用的(DRY 原则)
- 因为您可以更轻松地测试代码
自定义回购函数
public function findDestinationWithoutAudio() {
$query= "SELECT d
FROM HearWeGoHearWeGoBundle:Destination d
WHERE d NOT IN (SELECT IDENTITY(a.destination)
FROM HearWeGoHearWeGoBundle:Audio a)"
;
return $this->getEntityManager()->createQuery($query)->getResult();
}
如果您想知道为什么要使用 IDENTITY()
函数而不是直接使用外键:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#dql-functions
我有 2 个实体:音频和目标
音频中:
/**
* @ORM\OneToOne(targetEntity="HearWeGo\HearWeGoBundle\Entity\Destination", inversedBy="audio")
* @Assert\NotBlank(message="This field must be filled")
*
*/
private $destination;
我创建了一个名为 AddAudioType 的表单类型,用于将音频上传到数据库
<?php
namespace HearWeGo\HearWeGoBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use HearWeGo\HearWeGoBundle\Entity\Audio;
class AddAudioType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name','text')
->add('content','file')
->add('destination','entity',array('class'=>'HearWeGoHearWeGoBundle:Destination','property'=>'name'))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array('data_class'=>"HearWeGo\HearWeGoBundle\Entity\Audio"));
}
public function getName()
{
return 'add_audio';
}
}
?>
在控制器中
/**
* @Route("/admin/add/audio",name="add_audio")
*/
public function addAudioAction(Request $request)
{
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')){
return new Response('Please login');
}
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
$audio=new Audio();
$form=$this->createForm(new AddAudioType(),$audio,array(
'method'=>'POST',
'action'=>$this->generateUrl('add_audio')
));
$form->add('submit','submit');
if ($request->getMethod()=='POST')
{
$form->handleRequest($request);
if ($form->isValid())
{
$destination=$this->getDoctrine()->getRepository('HearWeGoHearWeGoBundle:Destination')
->findByName($form->get('destination')->getData()->getName());
$audio->setDestination($destination);
$name=$_FILES['add_audio']['name']['content'];
$tmp_name=$_FILES['add_audio']['tmp_name']['content'];
if (isset($name))
{
if (!empty($name))
{
$location=$_SERVER['DOCUMENT_ROOT']."/bundles/hearwegohearwego/uploads/";
move_uploaded_file($tmp_name,$location.$name);
$audio->setContent($location.$name);
$em=$this->getDoctrine()->getEntityManager();
$em->persist($audio);
$em->flush();
return new Response('Audio '.$audio->getName().' has been created!');
}
}
}
}
return $this->render('@HearWeGoHearWeGo/manage/addAudio.html.twig',array('form'=>$form->createView()));
}
在 AddAudioType 中,我声明它从目标实体 table 获取所有记录并允许用户选择其中之一,然后将其保存到数据库
现在还有一件事我必须处理:因为 Audio 和 Destination 之间的关系是一对一的,所以不允许用户选择已经出现在 Audio 中的 Destination table。现在在 AddAudioType 中,我不想从 Destination table 获取所有记录,而只是想获取尚未出现在 Audio table 中的一些记录。我应该怎么做?
当您在表单生成器中执行操作时
->add('destination', 'entity', array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'property'=>'name'
));
你是说你想要所有可能的 Destination
个实体
如果要过滤,有两种可能
第一个(推荐)
编写您自己的方法,将已经“关联”的 Destinations
排除到 DestionationRepository
中。如果您不知道什么是存储库或者不知道如何编写存储库,请参阅此document。方法实现留给你作为练习(不,真的,我不了解所有实体,所以我无法做出任何猜测)
完成此操作后,您必须将 DestinationRepository
作为选项传递给您的表单( 需要 我想 [参见 setRequired()
方法下面]),所以,像这样(我将省略无趣的代码)
//AddAudioType
<?php
[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
$destination_repo = $options['dr'];
$builder->[...]
->add('destination','entity',array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'choices'=> $destination_repo->yourCustomRepoFunctionName(),
'property'=>'name'));
}
$resolver->setRequired(array(
'dr',
));
现在您已经为您的表单设置了所有内容,您需要将 DestinationRepository
传递给您的表单。你怎么做到的?
确实很简单
//In controller you're instatiating your form
[...]
public function addAudioAction()
{
[...]
$destination_repo = $this->getDoctrine()
->getManager()
->getRepository('HearWeGoHearWeGoBundle:Destination');
$form=$this->createForm(new AddAudioType(), $audio, array(
'method' => 'POST',
'action' => $this->generateUrl('add_audio'),
'dr' => $destination_repo,
));
}
只要你写了一个好的“过滤器”方法(即:你用 NOT IN
子句排除了所有 Destinations
,它得到了其他 table)
第二个
您只需将您的方法写入表单
//AddAudioType
use Doctrine\ORM\EntityRepository;
<?php
[...]
public function buildForm(FormBuilderInterface $builder, array $options)
{
$destination_repo = $options['dr'];
$builder->[...]
->add('destination','entity',array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'choices'=> function(EntityRepository $repository) use ($someParametersIfNeeded) {
return $repository->createQueryBuilder('d')
->[...];},
'property'=>'name'));
}
在第二种情况下,createQueryBuilder
也没有实现,留给你。您需要记住一件事:choices
将需要一个查询构建器,所以不要调用 ->getQuery()
和 ->getResult()
为什么是拳头?
- 自定义函数应始终保留在存储库中。因此,您正在将一些代码写入必须的位置(请参阅下面的要点以了解方式)
- 因为这样的代码是可重用的(DRY 原则)
- 因为您可以更轻松地测试代码
自定义回购函数
public function findDestinationWithoutAudio() {
$query= "SELECT d
FROM HearWeGoHearWeGoBundle:Destination d
WHERE d NOT IN (SELECT IDENTITY(a.destination)
FROM HearWeGoHearWeGoBundle:Audio a)"
;
return $this->getEntityManager()->createQuery($query)->getResult();
}
如果您想知道为什么要使用 IDENTITY()
函数而不是直接使用外键:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#dql-functions