【问题标题】:Symfony2 Entity Form Type gets dataSymfony2 Entity Form Type 获取数据
【发布时间】:2023-03-20 22:32:01
【问题描述】:

我有 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 中,我声明它从目标实体表中获取所有记录并允许用户选择其中一个,然后将其持久化到数据库中

现在我必须处理另一件事:因为 Audio 和 Destination 之间的关系是一对一的,所以不允许用户选择已出现在 Audio 表中的 Destination。现在在 AddAudioType 中,我不想从 Destination 表中获取所有记录,而只想获取一些尚未出现在 Audio 表中的记录。我该怎么做?

【问题讨论】:

    标签: forms symfony types get entity


    【解决方案1】:

    当您在表单构建器中进行操作时

    ->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,把钥匙放到另一个表中)


    第二个

    您只需将方法写入表单

    //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 需要一个查询构建器,所以不要调用 -&gt;getQuery()-&gt;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

    【讨论】:

    • 我按照第一个解决方案,我在DestinationRepository中写了如下方法:public function findDestinationWithoutAudio() { $query='SELECT d FROM HearWeGoHearWeGoBundle:Destination d WHERE d NOT IN (SELECT a.destination FROM HearWeGoHearWeGoBundle:Audio a)'; return $this-&gt;getEntityManager()-&gt;createQuery($query)-&gt;getResult(); }我遇到了新问题:Error: Invalid PathExpression. Must be a StateFieldPathExpression.在Audio实体中,$destination是Destination类型的实例,所以我可以'不要在查询中使用id
    • @necroface: 和...? (顺便说一句,我不确定你的退货声明)
    • 我编辑了上面的评论,它与createQuery有关
    • 错误卡在查询中。而且我不知道在这种情况下如何编写正确的查询
    • 我要挖出这个老问题来问一件事:如果我的customRepoFunction有一些参数,例如:public function findByAudioId($id) { return $this-&gt;getEntityManager()-&gt;createQuery('SELECT d FROM HearWeGoHearWeGoBundle:Destination d,HearWeGoHearWeGoBundle:Audio a WHERE d.id=IDENTITY (a.destination)')-&gt;getResult(); }我会在'choices'=&gt; $destination_repo-&gt;yourCustomRepoFunctionName()里​​面放什么@你能再帮帮我吗
    猜你喜欢
    • 2013-06-22
    • 2015-10-18
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 2016-05-19
    • 2016-01-27
    相关资源
    最近更新 更多