Symfony \ Doctrine createQueryBuilder () выбирает «не в» из отношения OneToMany - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть три существа: трофей |КонкурсСезон

Одно соревнование создается для одного трофея за один сезон (не может быть двух соревнований с одинаковой комбинацией "сезон + трофей").

Соревнование как отношение ManyToOne с трофеем, исвязь ManyToOne с Season.

Trophy и Season не имеют прямого отношения.

Я хочу отобразить два выпадающих списка на странице, содержание второго зависит от значения первого: В первом раскрывающемся списке можно выбрать тип трофея (который является свойством объекта трофея), во втором раскрывающемся списке должны быть указаны сезоны, которые «все еще доступны» для выбранного типа трофея (что означает «перечислить все сезоны, в которых нет соревнований за это»). Тип трофея ")

У меня почти все работает (слушатель в Formtype, ajax и т. д.) Я создал специальную функцию allWithoutThisCompetitionType () в SeasonRepository. Функция вызывается правильно каждый раз, когда пользователь выбирает новое значение в раскрывающемся меню, НО ... Я ничего не знаю ни о SQL, ни о dql, поэтому я изо всех сил пытаюсь найти правильную формулировку для моего запроса. Я пытался с notin (), с "sub" или "вложенными" запросами ... Я точно не знаю, что я делаю ...

Как я могу сделать что-то подобное? :

$qb = $em->getRepository(\App\Entity\Seasonmanager\Season::class)->createQueryBuilder('s')
            ->where('s.competitions.trophy != :trophy')
    ->setParameter('trophy', $trophy);

= Вот все сезоны, для которых с этим трофеем еще не создано ни одного соревнования

Спасибо за вашу помощь.

Трофейное лицо:

/**
 * @ORM\Entity(repositoryClass="App\Repository\Seasonmanager\TrophyRepository")
 */
class Trophy
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $uniqueid;


 // other properties here...    
//////////////////////////////////////////////////////////////////////////////////

//// LIAISONS VERS D'AUTRES ENTITY ////

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Seasonmanager\Competition", mappedBy="trophy", orphanRemoval=true)
     */
    private $competitions;

Объект конкурса:

/**
 * @ORM\Entity(repositoryClass="App\Repository\Seasonmanager\CompetitionRepository")
 * @UniqueEntity(
 *    fields={"trophy","season"},
 *    errorPath="trophy",
 *    message="Une compétition existe déjà pour ce trophée et cette saison"
 * )
 */
class Competition
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

// other properties here...

//////////////////////////////////////////////////////////////////////////////////

//// LIAISONS VERS D'AUTRES ENTITY ////

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Seasonmanager\Trophy", inversedBy="competitions")
     * @ORM\JoinColumn(nullable=false)
     */
    private $trophy;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Seasonmanager\Season", inversedBy="competitions")
     * @ORM\JoinColumn(nullable=false)
     */
    private $season;

Объект сезона:

/**
 * @ORM\Entity(repositoryClass="App\Repository\Seasonmanager\SeasonRepository")
 * @UniqueEntity("yearin")
 */
class Season
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="integer", length=4)
     */
    private $yearout;

    /**
     * @ORM\Column(type="string", length=8)
     */
    private $uniqueid;

// other properties here...

//////////////////////////////////////////////////////////////////////////////////

//// LIAISONS VERS D'AUTRES ENTITY ////

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Seasonmanager\Competition", mappedBy="season", orphanRemoval=true)
     */
    private $competitions;

Репозиторий Season, куда я пытаюсь добавить свой запрос:

namespace App\Repository\Seasonmanager;

use App\Entity\Seasonmanager\Season;
use App\Entity\Seasonmanager\Trophy;
use App\Entity\Seasonmanager\Competition;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;

/**
 * @method Season|null find($id, $lockMode = null, $lockVersion = null)
 * @method Season|null findOneBy(array $criteria, array $orderBy = null)
 * @method Season[]    findAll()
 * @method Season[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class SeasonRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Season::class);
    }

    public function allWithoutThisCompetitionType($type): array
    {
        $em = $this->getEntityManager();
        $trophys = $em
            ->getRepository(Trophy::class)
            ->findBy(['uniqueid' => $type],['id'=>'DESC'])
        ;
        $trophy = reset($trophys);

        $qb = $em->getRepository(\App\Entity\Seasonmanager\Season::class)->createQueryBuilder('s')
            ->where('s.competitions.trophy',  $trophy);
        $query = $qb->getQuery();
        $result = $query->getResult();
        $donnees = $result;
        return $donnees;

    }

1 Ответ

0 голосов
/ 04 ноября 2019

Вот запрос, но я не на 100% уверен, что он будет соответствовать вашим потребностям.
Дайте мне знать в комментарии, если что-то не так, я отредактирую свой ответ.

public function allWithoutThisCompetitionType($trophy) {
    // Split init from the rest of the query in case you need to use `$qb->expr()`
    $qb=$this->createQueryBuilder("season");

    $qb->leftJoin("season.competition", "competition") // Join competition
       ->join("competition.trophy", "trophy") // Join Trophy
       ->andWhere($qb->expr()->orX( // Or (either one of the following satements)
            $qb->expr()->isNull("competition.id"),
            $qb->expr()->notIn("trophy.uniqueid", ":trophy")))
       ->setParameter("trophy", $trophy);

    return $qb->getQuery()->getResult();
}
...