Reputation: 3465
I have 2 entities: Audio and Destination
In Audio:
/**
* @ORM\OneToOne(targetEntity="HearWeGo\HearWeGoBundle\Entity\Destination", inversedBy="audio")
* @Assert\NotBlank(message="This field must be filled")
*
*/
private $destination;
I created a Form Type name AddAudioType used to upload an audio to database
<?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';
}
}
?>
In Controller
/**
* @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()));
}
In AddAudioType, I declared so that it gets all records from Destination entity table and allows user to choose one of them, then persist it to database
Now there's something another I have to handle: Because relationship between Audio and Destination is one-to-one, user is not allowed to choose a Destination which already appeared in Audio table. Now in AddAudioType, I don't want to get all records from Destination table, but only some that hasn't appeared in Audio table yet. How should I do it?
Upvotes: 0
Views: 385
Reputation: 29912
When you do in your form builder
->add('destination', 'entity', array(
'class'=>'HearWeGoHearWeGoBundle:Destination',
'property'=>'name'
));
you're saying that you want all of possible Destination
entities
If you want to filter them, you have two possibilities
Write your own method to exclude already "associated" Destinations
into DestionationRepository
. If you don't know what is a repository or you don't know how to write one, please refer to this document. Method implementation is left to you as an exercise (No, really, I don't know all entities so I cannot make any guess)
Once you've done this, you have to pass DestinationRepository
to your form, as an option (required I suppose [see setRequired()
method below]), so, something like this (I'll omit uninteresting code)
//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',
));
Now that you have setted all for your form, you need to pass DestinationRepository
to your form. How do you that?
It's quite simple indeed
//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,
));
}
It's going to work like a charm as long as you write a good "filter" method (ie.: you exlude with NOT IN
clause all Destinations
that got the key into other table)
You simply write your method into the form
//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'));
}
In this second case, createQueryBuilder
is also not implemented and left to you. One thing you need to remember: choices
will need a query builder, so don't call ->getQuery()
and ->getResult()
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();
}
If you want to know why you should use IDENTITY()
function and not foreign key directly: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#dql-functions
Upvotes: 1