how to join on many-to-many relations using querybuilder? - symfony

I am trying to rebuild it in Symfony2 on a many-to-many relationship between users and accounts with query builder but I am failing. this is the DQL
return $er->createQueryBuilder('a')
->leftJoin('\FEB\UserBundle\Entity\Userr', 'u')
->where('a.id = :id')
->setParameter('id', $options['pepe']);
This is the entities:
user.php
namespace FEB\UserBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="feb_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// tu propia lógica
}
}
Account.php
namespace FEB\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Account
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="FEB\UserBundle\Entity\AccountRepository")
*/
class Account
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* Many-To-Many, Unidirectional
*
* #var ArrayCollection $idusr
*
* #ORM\ManyToMany(targetEntity="\FEB\UserBundle\Entity\User")
* #ORM\JoinTable(name="accounts_users",
* joinColumns={#ORM\JoinColumn(name="account_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="usr_id", referencedColumnName="id")}
* )
*/
private $idusr;
public function __construct() {
$this->idusr = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set idusr
*
* #param string $idusr
* #return Account
*/
public function setIdusr($idusr)
{
$this->idusr = $idusr;
return $this;
}
/**
* Get idusr
*
* #return integer
*/
public function getIdusr()
{
return $this->idusr;
}
When I execute the DQL I got all the records of "account" table and not the join:
The SQL statement I want to run would be this:
SELECT *
FROM Account a
LEFT JOIN accounts_users au ON ( au.usr_id = a.id )
WHERE au.usr_id = 1
How can I fix it?
Edit 1:
The idea is retrieve the result to populate a drop-down in account form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('titulo')
->add('tweet', 'textarea')
->add('photo', 'file', array('required' => false))
->add('tags', 'entity', array(
'class' => 'FEBTagsBundle:tag',
'property' => 'tag',
'empty_value' => 'Selecciona tags',
'multiple' => true))
->add('idaccount', 'entity', array(
'class' => 'FEBUserBundle:Account',
'property' => 'username',
'query_builder' => function(EntityRepository $er ) use ($options) {
return $er->createQueryBuilder('a')
->leftJoin('\FEB\UserBundle\Entity\User', 'u')
->where('a.id = :id')
->setParameter('id', $options['pepe']);
//->andWhere('w.visible = 1')
//->andWhere('w.booked = 0');
;},
'empty_value' => 'Selecciona account',
'multiple' => false))
;
}
EDIT2: More info.
The goal is:
From the id of the "feb_user" table, I get the username of the "Account" table. The table feb_user and Account tables are related through the "accounts_users" table.

Correct me if I'm wrong, but you can just query the user like:
$Account = $er->find(<<some_id>>);
Now you can fetch the account and can access the User entity:
$User = $Account->getIduser();

I finally found the solution!
My mistake was in the way I created the DQL. In the leftjoin sentence I referred to the entity, andthe correct way is making reference to the variable that linked the two entities. Would be as follows:
->add('idaccount', 'entity', array(
'class' => 'FEBUserBundle:Account',
'property' => 'username',
'query_builder' => function(EntityRepository $er ) use ($options) {
return $er->createQueryBuilder('a')
->leftJoin('a.idusr', 'u')
->where('u.id = :id')
->setParameter('id', $options['pepe']);
},
'empty_value' => 'Selecciona account',
'multiple' => false));
Thanks to all!!!!

Related

Symfony - Can't get a way to read the property (PropertyAccessor)

I develop with symfony a form for create tickets but when i try i got this error:
my function buildform from the file tickettype.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Titre', TextType::class)
->add('Message', TextType::class)
->add('Date', DateTimeType::class, ['data' => new \DateTime()] )
->add('Demandeur', EntityType::class, [
'class' => Client::class,
'choice_label' => 'Nom',
])
->add('Agent', EntityType::class, [
'class' => Dealer::class,
'choice_label' => 'Nom',
])
->add('Etat_Ticket', EntityType::class, [
'class' => Etat::class,
'choice_label' => 'Statut',
]);
}
and in the controller :
/**
* #Route("/add/", name="add_ticket")
*
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function addTicketAction(Request $request)
{
$ticket = new Ticket();
$form = $this->createForm(TicketType::class, $ticket);
$form->add('send', SubmitType::class, ['label' => 'créé un nouveau ticket']);
$form->handleRequest($request);
if($form->isSubmitted()){
$ticket->setDate(new \DateTime());
$em = $this->getDoctrine()->getManager();
$em->persist($ticket);
$em->flush();
return $this->redirectToRoute('List_ticket');
}
return $this->render("add.html.twig", array('form' => $form->createView()));
}
and my entity Ticket have this property:
/**
* #ORM\ManyToOne(targetEntity=Etat::class, inversedBy="Etat_Ticket")
* #ORM\JoinColumn(nullable=false)
*/
private $Etat_Ticket;
link to the entity Etat which look like this :
/**
* Etat
*
* #ORM\Table(name="etat")
* #ORM\Entity
*/
class Etat
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="statut", type="string", length=255, nullable=false)
*/
private $statut;
public function getId(): ?int
{
return $this->id;
}
public function getStatut(): ?string
{
return $this->statut;
}
public function setStatut(string $statut): self
{
$this->statut = $statut;
return $this;
}
}
You don't have a getter for Etat_Ticket property, so symfony (and that's a PHP common rule, when the property is not public) can't read its value from outside class scope. Symfony Form component, here, is trying by default to use the getter or access the property directly if it were public, and as neither getter nor public property are found, it symply doesn't know how to retrieve the value.
You can feed the form by yourself (docs) or use property_path.
Remember also that binding entities (or in general the domain model) directly to a form is good for RAD (rapid application development) but not so good in the long term. I would suggest to use a sort of DTO in order to read and write from and to the model (take a look here in order to get an idea about this concept)

symfony - dropdown menu doesn't select the option

I made a page on symfony to administrate some products with a dropdown menu linked to a category table.
The categoryid is well saved on the product, but the dropdown never select the good option, I don't find why.
Here is the category part in my class Dproduct :
/**
* #ORM\ManyToOne(targetEntity=RCategory::class, inversedBy="products")
* #ORM\JoinColumn(name="categoryId", referencedColumnName="categoryId", onDelete="CASCADE")
*/
private $categoryId;
public function getCategoryId(): ?RCategory
{
return $this->categoryId;
}
public function setCategoryId(?RCategory $categoryId): self
{
$this->categoryId = $categoryId;
return $this;
}
here is my class RCategory:
/**
* RCategory
*
* #ORM\Table(name="r_category")
* #ORM\Entity
*/
class RCategory
{
/**
* #var int
*
* #ORM\Column(name="categoryId", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $categoryId;
/**
* #var string
*
* #ORM\Column(name="categoryLib", type="string", length=50, nullable=false)
*/
private $categoryLib;
/**
* #Gedmo\Slug(fields={"categoryLib"})
* #ORM\Column(type="string", length=128, unique=true)
*/
public function getCategoryId(): ?int
{
return $this->categoryId;
}
public function getCategoryLib(): ?string
{
return $this->categoryLib;
}
public function setCategoryLib(string $categoryLib): self
{
$this->categoryLib = $categoryLib;
return $this;
}
here is my buildForm function :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('categoryId', ChoiceType::class, [
'mapped' => false,
'choices' => $options['choiceCategory'],
'label' => 'Catégorie'
])
->add('productLib', TextType::class, [
'label' => 'Libellé',
])
->add('Enregister', SubmitType::class)
;
}
And my choiceCategory function :
public function choiceCategory(){
$choices = [];
$categories = $this->getCategory();
foreach ($categories as $categorie) {
$choices[$categorie->getCategorylib()] = $categorie->getCategoryid();
}
return $choices;
}
And finaly my controller :
$product = $this->getDoctrine()
->getRepository('App:DProduct')
->findOneBy(array('slug' => $slug));
...
$form = $this->createForm(productType::class, $product, array('choiceCategory'=>$categoryController->choiceCategory()));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
... Data is well saved ...
}
return $this->render(
'form/meuble.html.twig',
array(
'form' => $form->createView(),
'titlePage' => $titlePage,
'product' => $product
)
);
Does anyone see where is the problem ?
Thanks,
Best regards,
Matthieu
You are using an unmapped field, therefore it won't set any data based on the product you are editing.
You can set the data with de data option
$product = $builder->getData();
...
->add('categoryId', ChoiceType::class, [
'mapped' => false,
'choices' => $options['choiceCategory'],
'label' => 'Catégorie'
'data' => $product->getCategory(),
])
U might be able to use a mapped field and use the EntityType instead of the ChoiceType to build the choices. Notice the choice_label and query_builder options.

How to set related entity id in one to many relationship Symfony?

I am trying to persist two entities that have OneToMany and ManyToOne relationships.
I'm trying to embed a collection of forms inside a form.
I have a many to one related entities and everytime I create a new CurriculumVitae which is related to Candidat the column candidat_id_id is null.
Only the entity CurriculumVitae is successfully created and persisted except the Candidat id in the data datatable.
CurriculumVitae Table
id | titre | candidat_id_id | id_education
candidat_id_id is: null
id_education has this value: Doctrine\Common\Collections\ArrayCollection#000000003d585f990000000052235238
Education Table is empty
id | description | id_curriculum_vitae_id
My problem is with the id_curriculum_vitae_id and the id_education.
CurriculumVitae Entity:
/**
* CurriculumVitae
*
* #ORM\Table(name="curriculum_vitae")
* #ORM\Entity(repositoryClass="GE\CandidatBundle\Repository\CurriculumVitaeRepository")
*/
class CurriculumVitae
{
/**
* #var Candidat
*
* #ORM\ManyToOne(targetEntity="GE\CandidatBundle\Entity\Candidat")
*/
protected $candidatId;
/**
* #var Education
* #ORM\OneToMany(targetEntity="GE\CandidatBundle\Entity\Education", mappedBy="idCurriculumVitae", cascade={"persist", "remove"})
* #ORM\Column(name="id_education")
*/
protected $educations;
/**
* Add education
*
* #param \GE\CandidatBundle\Entity\Education $education
*
* #return CurriculumVitae
*/
public function addEducation(\GE\CandidatBundle\Entity\Education $education)
{
$this->educations[] = $education;
$education->setCurriculumVitae($this);
return $this;
}
/**
* Remove education
*
* #param \GE\CandidatBundle\Entity\Education $education
*/
public function removeEducation(\GE\CandidatBundle\Entity\Education $education)
{
$this->educations->removeElement($education);
}
}
Education Entity:
/**
* Education
*
* #ORM\Table(name="education")
* #ORM\Entity(repositoryClass="GE\CandidatBundle\Repository\EducationRepository")
*/
class Education
{
...
/**
* #var CurriculumVitae
* #ORM\ManyToOne(targetEntity="GE\CandidatBundle\Entity\CurriculumVitae")
*/
private $idCurriculumVitae;
}
CurriculumVitaeController :
class CurriculumVitaeController extends Controller
{
/**
* Creates a new curriculumVitae entity.
*
* #Route("/candidat/cv/ajouter", name="cv_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$curriculumVitae = new Curriculumvitae();
$form = $this->createForm('GE\CandidatBundle\Form\CurriculumVitaeType', $curriculumVitae);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($curriculumVitae);
$em->flush();
$request->getSession()
->getFlashBag()
->add('infoCv', 'Votre cv a été bien enregistrée.');
return $this->redirectToRoute('cv_show', array('id' => $curriculumVitae->getId()));
}
return $this->render('curriculumvitae/new.html.twig', array(
'curriculumVitae' => $curriculumVitae,
'form' => $form->createView(),
));
}
}
CurriculumVitaeType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('candidat', EntityType::class, array(
'class' => 'GECandidatBundle:Candidat',
'choice_label' => 'id',
'multiple' => false,
))
->add('educations',
CollectionType::class, [
'entry_type' => EducationType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
'label' => 'Educations:'
]
)
;
}
Try this code and update your database's schema
/**
* #var CurriculumVitae
* #ORM\ManyToOne(targetEntity="GE\CandidatBundle\Entity\CurriculumVitae")
*#ORM\JoinColumn(name="candidatId",referencedColumnName="id",onDelete="SET NULL")
*/
private $idCurriculumVitae;
Sorry, i found my problem.
the id must be defined in the Controller.
$curriculumVitae->setCandidat($candidat);

Symfony 2 - Form select options database

I'm beginner in Symfony 2.
I'm trying to display a form with a "select" where is the "options" from a query.
I put the following code in my form :
use Doctrine\ORM\EntityRepository;
use Bloc\MainBundle\Entity\Table;
use Bloc\MainBundle\Entity\Table2;
public function addAction(Request $request)
{
$table = new Table();
$form = $this->createFormBuilder($table , array('attr' => array('role' => 'form')))
->add('num', 'integer', array('label' => 'Numéro', 'attr' => array('class' => 'form-control')))
->add('nom_emetteur', 'text', array('label' => 'Emetteur', 'attr' => array('class' => 'form-control')))
->add('numero', 'entity', array('class' => 'BlocMainBundle:Table2', 'property' => 'numero'))
...
}
And I have the following error:
Neither the property "numero" nor one of the methods "getNumero()", "isNumero()", "hasNumero()", "__get()" or "__call()" exist and have public access in class "Bloc\MainBundle\Entity\Table".
I understand that the error tells me that "numero" is not in the entity Table but I question the entity Table2.
I must miss something, but I do not know where ...
My entity definition looks like this :
Table 1:
<?php...
class Table
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="num", type="integer")
*/
private $num;
//Getter and setter...
}
Table 2
<?php
namespace Bloc\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Fournisseur
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Bloc\MainBundle\Entity\Table2Repository")
*/
class Table2
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="numero", type="integer")
*/
private $numero;
/**
* Set numero
*
* #param integer $numero
* #return Fournisseur
*/
public function setNumero($numero)
{
$this->numero = $numero;
return $this;
}
/**
* Get numero
*
* #return integer
*/
public function getNumero()
{
return $this->numero;
}
...
}
Can you help me please ?
If you do not have the relationship set then you need to tell the FormBuilder to not map it to a field.
->add('numero', 'entity', array(
'mapped' => false,
'class' => 'BlocMainBundle:Table2',
'property' => 'numero',
));
To accomplish the options the way that you want (using multiple fields for the option text) you need to use a choice type and build your options list like this:
->add('numero', 'choice', array(
'mapped' => false,
'choices' => $this->buildChoices()
));
protected function buildChoices() {
$choices = [];
$table2Repository = $this->getDoctrine()->getRepository('BlocMainBundle:Table2');
$table2Objects = $table2Repository->findAll();
foreach ($table2Objects as $table2Obj) {
$choices[$table2Obj->getId()] = $table2Obj->getNumero() . ' - ' . $table2Obj->getName();
}
return $choices;
}
you can use this solution. Its a simply and from documentation of symfony2. I m use this
->add('numero', 'entity', array(
'class' => 'BlocMainBundle:Table2',
'choice_label' => 'numero' // MAGIC read next paragraph, it is a private variable
))
Like is in documentation writed:
If the entity object does not have a __toString() method the choice_label option is needed.
Use this solution because its native symfony solution for this situations :)
I hope i will help you or the other people
If you need information's table, you could create a constructor in your Form class
in your controller :
$emForm = $this->getDoctrine()->getRepository('RelacionesDoctrineBundle:Adolecente');
$asignatura = new AsignaturasType($emForm);// your form class
in your form class
class AsignaturasType extends AbstractType {
protected $repository;
function __construct($repository)
{
$this->repository = $repository;
}
}
and done! you use it:
$findAdolecente = $this->repository->findAll();

Exclude certain values in ManytoOne Array Colletion/Formbuilder

I am having trouble getting a formular in Symfony2 where I want to exclude certain values within an array collection - or I have to say I don't know how (where to exclude them).
This is my newTag Action:
public function newTagAction()
{
$tag = new Tag();
$form = $this->createForm(new tagType(), $tag);
return $this->render('MyMyBundle:Admin:newTag.html.twig', array('form' => $form->createView()));
}
And Tag.php Entity, which has a ManyToOne relation to Movie and vice verca (Movie->Tag = OneToMany):
class Tag
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\ManyToOne(targetEntity="Movie", inversedBy="videotags")
* #ORM\JoinColumn(name="movie_id", referencedColumnName="id")
*/
protected $movie;
// ...
In the TagType.php form it says:
class TagType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name')
->add('movie') // This is where certain movies should be excluded, it displays an array collection of all movies
;
}
Any help appreciated!
Thanks!
You can use custom queries to get only the results you want.
It's explained in the documents. Here is a quick example:
$builder->add('movie', 'entity', array(
'class' => 'MyMovieBundle:Movie',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.name = ?1');
},
));

Resources