How to join multiple entities on a foreign ID in Symfony 4 using a query builder?

 ̄綄美尐妖づ 提交于 2019-12-01 20:23:33

There are several minor problems in your code, more on that later.

Here is \App\Repository\CabinetRepository::findByBedroom:

    public function findByBedroom(Bedroom $bedroom) //use joins??
    {
        return $this->createQueryBuilder('cabinet')
            ->join('cabinet.kitchen', 'kitchen')
            ->join('kitchen.house', 'house')
            ->join('house.bedroom', 'bedroom')
            ->addSelect('cabinet')
            ->andWhere('bedroom = :bedroom')
            ->setParameter('bedroom', $bedroom)
            ->getQuery()
            ->getResult();
    }

For bedroom entity with ID 815 the code above returns the following (formatted as symfony/var-dumper would do that):

array:2 [▼
  0 => Cabinet {#387 ▼
    -id: 88
    -shopUrl: "co.m"
    -account_id: null
    -kitchen: Kitchen {#354 ▼
      +__isInitialized__: false
      -cabinet: null
      -house: null
      -id: 2
      -name: null
       …2
    }
  }
  1 => Cabinet {#364 ▼
    -id: 1
    -shopUrl: "ur.l "
    -account_id: null
    -kitchen: Kitchen {#370 ▼
      +__isInitialized__: false
      -cabinet: null
      -house: null
      -id: 55
      -name: null
       …2
    }
  }
]

Note: house references are null because of lazy loading.

So, small problems in your code:

  1. Your query in CabinerRepository was doing wrong joins. For correct joins see code above.

  2. That query referring to unknown field time. I have removed that reference.

  3. And also was using bedroom ID instead of bedroom entity.

  4. Your Kitchen.php is incomplete, it refers Collection and ArrayCollection classes, but there are no corresponding use directives. Just add this after namespace before class:

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

Update: here is how to get repository reference:

public function myControllerAction(/* other parameters */, CabinetRepository $cabRepo)
{
    $cabinet = $cabRepo->find($id);
    // OR, if you don't want to add parameter for some reason:
    $cabRepo = $this->getDoctrine()->getRepository(Cabinet::class);
    $cabinet = $cabRepo->find($id);
}

In your debug bar in symfony you should probably be seeing some errors in doctrine. These won't show up in PHPStorm. You need to rename $kitchen and $bedroom to their plural forms $kitchens and $bedrooms (and change your getters/setters to match) since this is how you define things in the owning side of your doctrine relationships.

A simpler approach than your repository method would be to do what you want in your controller to let doctrine do your heavy lifting:

$cabinets = [];

$house = $bedroom->getHouse();
$kitchens = $house->getKitchens();
foreach ($kitchens as $kitchen) {
    $kitchenCabinets = $kitchen->getCabinets();
    $cabinets = array_merge($cabinets, $kitchenCabinets);
}

First I think because you joining with both entities at the same time in this

...
            ->join('cabinet.bedroom', 'bedroom')
            ->join('cabinet.kitchen', 'kitchen')
...

and because that will be with INNER JOIN, it will require that cabined is required both bedroom and kitchen cabinet.

For that there is few solutions to work through:

  • Proper one would be redesign you entities. I think it might not be hard to use Doctrine inheritance
  • you might change joins to left, so relation is not mandatory (will work, but in general its not good solution because of wrong design)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!