0

I have three entities : Trophy | Competition | Season

One Competition is created for one trophy for one season (you can't have two competitions with same combination "season + trophy").

Competition as a ManyToOne relation with Trophy, and a ManyToOne relation with Season.

Trophy and Season have no direct relation.

I want to display two dropdowns on a page with the content of the second one being dependent from the value of the first : First dropdown allow to select a trophy type (which is a property of Trophy entity), second dropdown must list seasons that are "still available" for trophy type selected (meaning by that "list all seasons for which there are no competition for this trophy type")

I've got almost all working (listener in the Formtype, ajax etc) I've created a specific function allWithoutThisCompetitionType() in SeasonRepository. Function is correctly called every-time user select a new value in dropdown BUT... I don't know anything about SQL nor dql, so I'm struggling to find the correct formulation for my query. I've tried with notin(), with "sub" or "nested" queries... I definitely don't know what I'm doing...

How can I do something like ? :

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

= Here are all the seasons for which no competition has been already created with this trophy

Thank you for your help.

Trophy entity :

/**
 * @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;

Competition entity :

/**
 * @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;

Season entity :

/**
 * @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;

The SeasonRepository where I try to add my query :

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;

    }
macbeb
  • 227
  • 2
  • 11
  • in which file is located your query? – Preciel Nov 04 '19 at 16:55
  • the query is in in SeasonRepository.php (the Repository of Season entity) – macbeb Nov 04 '19 at 17:11
  • What is the value of `$trophy`? A string? Number? What is the name of the property you're trying to match in `Trophy` class? – Preciel Nov 04 '19 at 17:21
  • $trophy is a Trophy entity (retrieved using the trophy type listed in first dropdown). – macbeb Nov 04 '19 at 17:23
  • So the propety matching this string in `Trophy` class is `name`? – Preciel Nov 04 '19 at 17:25
  • sorry I edited, my first answer was wrong – macbeb Nov 04 '19 at 17:26
  • $trophy is the entity Trophy "based on" which I need the list of Season that have no Competition with this Trophy... (not sure it's really clear) – macbeb Nov 04 '19 at 17:27
  • Not what I mean. `Trophy` entity is made of paramaters (id, name, year, etc). I want to know which of there property you're trying to match with your query. I would say `name` by default. – Preciel Nov 04 '19 at 17:29
  • More simple, can you please add your 3 entities to your question. Will make things faster – Preciel Nov 04 '19 at 17:30
  • I added the entities and the SeasonRepository. function allWithoutThisCompetitionType($type) receive a string ($type) which permits to retrieve the Trophy entity (saved in $trophy). Then with queryBuilder() I imagine I should be able to list all Season that have no related Competition linked to $trophy entity, but I don't know how to formulate this query (do I need a join() a not in()... etc ?) – macbeb Nov 04 '19 at 17:44

1 Answers1

-2

Here is the query, though, I'm not 100% sure it will match your need.
Let me know in comment if something is wrong, I will edit my answer.

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();
}
Preciel
  • 2,666
  • 3
  • 20
  • 45
  • Thank you so much... works almost perfectly. Only caveats is that its listing only seasons that have at least one competition related, season without any competition are not listed (and I would like to) – macbeb Nov 04 '19 at 18:11
  • Does `Season` with no `Trophy` are listed in `Competition` table anyway? Or you insert data into `Competition` only when you get a first `Trophy`? – Preciel Nov 04 '19 at 18:14
  • I create Trophy and Season on a separate page/process. Then I create Competitions and insert data (relations to Trophy and Season for this Competition) at this moment. I have a list of season without any competition yet, but I want this seasons also being listed (in fact I use these dropdowns to easy the competition creation process = on submit it will create a new competition based on the "trophy type" and the "season" selected (that's why I want to propose all seasons available for this potential new competition) – macbeb Nov 04 '19 at 18:21
  • @macbeb tested the updated query? Didn't got any news – Preciel Nov 06 '19 at 16:24
  • not exactly, but I went another way. Thanks a lot for your help – macbeb Nov 07 '19 at 17:26