Search code examples
symfonydql

Symfony join query with One-To-Many relation


I am quite new to symfony as in DQL. I have a problem with query, namely I want to compare the ID's between 'term_id' from table 'TermAssign' with 'id' from table Term and then, the one's who are matching are to be rendered on a template. Relation between Term and TermAssign is OneToMany. There is also a table Offer, which has relation OneToMany with table TermAssign.

This is my Term.php:

   <?php

    namespace App\OfferBundle\Entity;
    use App\OfferBundle\Repository\TermRepository;
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\Common\Collections\Collection;  
    use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=TermRepository::class)
 * @ORM\Table(name="term")
 */
class Term
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, nullable=true, name="term_description")
     */
    private $term_description;

    /**
     * @ORM\OneToMany(targetEntity=TermAssign::class, mappedBy="term")
     */
    private $assign;

    public function __construct()
    {
        $this->assign = new ArrayCollection();
    }

  function getId(): ?int
    {
        return $this->id;
    }

    public function getTermDescription(): ?string
    {
        return $this->term_description;
    }

    public function setTermDescription(?string $term_description): self
    {
        $this->term_description = $term_description;

        return $this;
    }

    /**
     * @return Collection|TermAssign[]
     */
    public function getAssign(): Collection
    {
        return $this->assign;
    }

    public function addAssign(TermAssign $assign): self
    {
        if (!$this->assign->contains($assign)) {
            $this->assign[] = $assign;
            $assign->setTerm($this);
        }

        return $this;
    }

    public function removeAssign(TermAssign $assign): self
    {
        if ($this->assign->removeElement($assign)) {
            // set the owning side to null (unless already changed)
            if ($assign->getTerm() === $this) {
                $assign->setTerm(null);
            }
        }

        return $this;
    }
}

This is Offer.php:

<?php

namespace App\OfferBundle\Entity;

use App\OfferBundle\Repository\OfferRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints\DateTime;

/**
 * @ORM\Entity(repositoryClass=OfferRepository::class)
 */
class Offer
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string")
     */
    private $title;

    /**
     * @ORM\Column(type="date", name="offer_date")
     */
    private $date;

    /**
     * @ORM\Column(type="string", unique=true)
     */
    private $number;

    /**
     * @ORM\Column(type="string")
     */
    private $description;

    /**
     * @ORM\OneToMany(targetEntity=TermAssign::class, mappedBy="offer")
     */
    private $terms;

    public function __construct()
    {
        $this->terms = new ArrayCollection();
    }

    /**
     * Getting offer's id
     */
    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * getting offer's Title
     */
    public function getTitle(): string
    {
        return $this->title;
    }

    /**
     * Setting offer's name
     */
    public function setTitle($title): self
    {
        $this->title = $title;

        return $this;
    }

    /**
     * getting offer's date
     */
    public function getDate(): ?\DateTime
    {
        return $this->date;
    }

    /**
     * Setting offer's date
     */
    public function setDate($date): self
    {
        $this->date = $date;

        return $this;
    }

    /**
     * Offer's number
     */
    public function getNumber() : string
    {
        return $this->number;
    }

    /**
     * Setting offer's number
     */
    public function setNumber($number): self
    {
        $this->number = $number;

        return $this;
    }

    /**
     * Offer's description
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Setting offer's description
     */
    public function setDescription($description): void
    {
        $this->description = $description;
    }

    /**
     * @return Collection|TermAssign[]
     */
    public function getTerms(): Collection
    {
        return $this->terms;
    }

    public function addTerm(TermAssign $term): self
    {
        if (!$this->terms->contains($term)) {
            $this->terms[] = $term;
            $term->setOffer($this);
        }

        return $this;
    }

    public function removeTerm(TermAssign $term): self
    {
        if ($this->terms->removeElement($term)) {
            // set the owning side to null (unless already changed)
            if ($term->getOffer() === $this) {
                $term->setOffer(null);
            }
        }

        return $this;
    }
}

And this is TermAssign.php:

<?php

namespace App\OfferBundle\Entity;

use App\OfferBundle\Repository\TermAssignRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=TermAssignRepository::class)
 */
class TermAssign
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity=Offer::class, inversedBy="terms")
     */
    private $offer;

    /**
     * @ORM\ManyToOne(targetEntity=Term::class, inversedBy="assign")
     */
    private $term;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getOffer(): ?Offer
    {
        return $this->offer;
    }

    public function setOffer(?Offer $offer): self
    {
        $this->offer = $offer;

        return $this;
    }

    public function getTerm(): ?Term
    {
        return $this->term;
    }

    public function setTerm(?Term $term): self
    {
        $this->term = $term;

        return $this;
    }


}

I did came up with query of this sort:

 /**
 * @return Term[] Returns an array of Term objects
 */
public function findByIdField():array
{
    $em = $this->getEntityManager();
    $query = $em->createQuery("SELECT t, a FROM App\OfferBundle\Entity\Term t JOIN t.term a WHERE a.term_id = t.id");
    return $query->getResult();
}

But it's of no use.

Also, this is part of my controller where I invoke query to be passed into the template:

OfferController.php

/**
 * @Route("/{id}", name="offer_show", methods={"GET"})
 */
public function show(Offer $offer, int $id): Response
{
    $termAssigns = $this->getDoctrine()
        ->getRepository(TermAssign::class)
        ->findBy(
            ['offer'=>$id]
        );
    $terms = $this->getDoctrine()
        ->getRepository(Term::class)
        ->findByIdField();
    $conditions = $this->getDoctrine()
        ->getRepository(Condition::class)
        ->findAll();

    return $this->render('offer/show.html.twig', [
        'offer' => $offer,
        'terms'=> $terms,
        'conditions'=>$conditions,
        'termAssigns'=>$termAssigns,
    ]);
}

The question is, what can I do to achieve something like

SELECT description FROM Term.t where 't.id'='ta.term_id'

'ta' is TermAssign table.


Solution

  • That was WAY much less complicated than I have imagined... I didn't have to create a new query, all I had to do was to import a TermAssign repository to show() function located in OfferController.php and use findBy() function to fetch terms from Term table. Solution below:

    OfferController.php:

    /**
         * @Route("/{id}", name="offer_show", methods={"GET"})
         */
        public function show(Offer $offer, int $id, TermAssign $terms): Response
        {
            **$termAssigns = $this->getDoctrine()
                ->getRepository(TermAssign::class)
                ->findBy(
                    ['offer'=>$id]
                );
    
            $terms = $this->getDoctrine()
                ->getRepository(Term::class)
                ->findBy(
                    ['id'=>$terms->getId()]
                );**
    
            $conditions = $this->getDoctrine()
                ->getRepository(Condition::class)
                ->findAll();
    
            return $this->render('offer/show.html.twig', [
                'offer' => $offer,
                'terms'=> $terms,
                'conditions'=>$conditions,
                'termAssigns'=>$termAssigns,
            ]);
        }