Doctrine entity manager find by empty array collection

Viewed 4009

I have an entity called Cycle, with a OneToMany association to CycleActeur (see code below).

I'd like to be able to fetch all Cycle objets in database with no CycleActeur objects associated, using a simple doctrine findBy* method from my controller.

That is to say something like this :

$manager = $this->getContainer()->get('doctrine.orm.entity_manager');
$cycleManager =  $manager->getRepository('ESI67Zen2Bundle:Cycle');
$cyclesWithNoCycleActeur = $cycleManager->findBy('acteurs', null);

Is there a way to do this without having to write a specific method in the CycleRepository ?

Extract from the Cycle class code

class Cycle {
  /**
   * @ORM\OneToMany(
   *      targetEntity="CycleActeur", 
   *      mappedBy="cycle", 
   *      orphanRemoval=true)
   */
  private $acteurs;
}

Extract from the Cycle class code

class CycleActeur {
 /**
  * @var Cycle Le cycle concerné
  * 
  * @ORM\ManyToOne(targetEntity="Cycle", inversedBy="acteurs")
  * @ORM\JoinColumn(name="cycle_id", referencedColumnName="id")
  * 
  */
  private $cycle;
}
4 Answers

Your Cycle entity is the inverse side of relationship and it's table in database has no 'acteurs' column, so you cannot use findBy(['acteurs'=>null]) or findByActeurs(null). But you can do something anyway:

$manager = $this->getContainer()->get('doctrine.orm.entity_manager');
$cycleManager =  $manager->getRepository('ESI67Zen2Bundle:Cycle');
$allCycles = $cycleManager->findAll();

$cyclesWithNoCycleActeur = [];
foreach($allCycles as $cycle)
{
    if($cycle->getActeurs()->isEmpty())
    {
        $cyclesWithNoCycleActeur[] = $cycle;
    }
}

In this case (to my mind) the best way is to use DQL's condition IS EMPTY:

  $manager
    ->createQueryBuilder()
    ->from(Cycle::class, 'cycle')
    ->select('cycle')
    ->andWhere('cycle.acteurs IS EMPTY')
    ->getQuery()
    ->getResult()
    ;

You can use this code in the EntityRepository or anywhere you have access to the EntityManager.

Source: Doctrine documentation.

There's a DQL function SIZE(), which according to Doctrine documentation:

SIZE(collection) - Return the number of elements in the specified collection

So you can use it as a condition like:

SIZE(acteurs) = 0

I'm not sure if it will work with a findBy method, but I would recommend to create a custom method in ESI67Zen2Bundle:Cycle's repository, to make it explicit what the code is doing. Its will work both for DQL Query and Query Builder.

$cyclesWithNoCycleActeur = $cycleManager->findBy(array('SIZE(acteurs)' => 0));

My 2 cents

Related