Ma Relation ManyToMany n’est pas persisté.

La persistance de la relation ManyToMany avec doctrine n’est pas bidirectionnelle.

Il y a un côté maitre et un côté esclave. Seule la sauvegarde du côté maitre entrainera la sauvegarde du côté esclave.

Exemple :

<?php

class Article
{

    /**
    * @ManyToMany(targetEntity="Tag", inversedBy="articles")
    * @JoinTable(name="article_tag")
    **/
    private $tags;

}

class Tag
{

    /**
    * @ManyToMany(targetEntity="Article", mappedBy="tags")
    **/
    private $articles;

}

Dans cet exemple, c’est la classe Article qui est maitresse.

Lorsque l’on persistera la classe Article, les liaisons avec la classe Tag seront persistées elle aussi. Ce n’est pas le cas quand on persiste la classe Tag (il faudra développer du code spécifique)

Les différents moyens d’exécution d’une requête Doctrine2

Pour exécuter une requête Doctrine, il y’a plusieurs façons de faire à partir du Query Builder Doctrine2.

Doctrine2: Récupérer une collection de résultats

Exemple de requête à exécuter:

  $q = $this->createQueryBuilder('p')
->where('p.state = :state')
->setParameter('state', $state);

Récupérer tous les posts valides.

$q->getQuery()->execute();

Va permettre de retourner une collection d’objets (\Doctrine\Common\Collections\ArrayCollection()) de notre entité Post.

execute() a un équivalent:

$q-&gt;getQuery()->getResult()

Doctrine2: Récupérer un seul résultat

Si nous souhaitons récupérer une seule entrée avec Doctrine dans Symfony2:

$q = $this->createQueryBuilder('p')
->where('p.id = :post')
->setParameter('post', $idPost);

Il suffit d’utiliser getSingleResult() ou getOneOrNullResult().

$q->getQuery()->getOneOrNullResult()

L’avantage de getOneOrNullResult() et qu’il retournera null si aucune donnée n’est trouvée, contrairement à getSingleResult() qui déclenchera une erreur.

Doctrine2: Récupérer uniquement une valeur

Dans le cas d’un count() par exemple, nous ne souhaitons récupérer qu’une seule valeur avec notre requête:

$q = $this->createQueryBuilder('p')
          ->select('COUNT(p)');
On exécute la requête du Query Builder avec getSingleScalarResult()
$q->getQuery()->getSingleScalarResult();

Doctrine2: Récupérer les données en tableau

Et si vous ne souhaitez pas récupérer vos données sous forme d’objet, vous pouvez les récupérer formatées en tableau:
   $q = $this->createQueryBuilder('p')
->where('p.state = :state')
->setParameter('state', $state);

Récupérer tous les posts valides.

$q->getQuery()->getScalarResult();
OU
$q->getQuery()->getArrayResult();

Créer une requête SQL native dans Symfony2 avec Doctrine2

Il peut être intéressant voir obligatoire dans certains cas complexes d’avoir recours aux requêtes SQL native directement dans Symfony2, tout en passant par l’ORM et en récupérant des objets à la suite de cette requête.

Voici un exemple d’utilisation dans un Repository Symfony2:

use Doctrine\ORM\Query\ResultSetMapping;
$rsm = new ResultSetMapping();
$rsm->addEntityResult('Novaway\Bundle\CmsBundle\Entity\Project', 'p');
$rsm->addFieldResult('p', 'id', 'id');
$rsm->addFieldResult('p', 'title', 'title');

$sql = 'SELECT p.id, p.title FROM project p JOIN project_related pr ON p.id = pr.related_project_id WHERE pr.project_id = ?';

$query = $this->_em->createNativeQuery($sql, $rsm);
$query->setParameter(1, $idProject);

$projects = $query->getResult();

Récupérer l’ID d’un objet dans un Form\Type Symfony2 pour le QueryBuilder Doctrine

Il peut vous arriver d’avoir besoin de connaître l’ID de l’objet édité dans un formulaire, et ce directement dans la classe xxxType.php (La classe de votre formulaire).

Voilà comment récupérer dans un premier temps l’ID de l’objet dans la méthode buildForm (dans notre exemple il s’agit d’un objet Tag):

public function buildForm(FormBuilder $builder, array $options)
{
$idTag= $builder->getData()->getId();

Une fois récupéré, il est possible de le passer dans le Query Builder Doctrine de la manière suivante:

$builder->add('parent', 'entity', array(
'class' => 'Novaway\\CmsBundle\\Entity\\Tag',
'query_builder' => function(EntityRepository $er) use ($idTag)
{
$qb = $er->createQueryBuilder('t')
->where('t.parent IS NULL');

if (!is_null($idTag)) {
$qb->where('t.id != :id')
->setParameter('id', $idTag);
}

return $qb->orderBy('t.title', 'ASC');
},
'required' => false,
'empty_value' => '= Parent ='
));

Voilà une astuce bien pratique pour afficher du contenu plus avancé dans les widgets entity par exemple.