Search code examples
phpsymfonydoctrinedoctrine-odm

symfony 4 - Semantical Error with relation ManyToMany


I have started a project with Symfony and I'm a beginner with this framework. I'm usually able to correct all my errors by reading forums and documentation but in this case, I can not understand the error.

I have a WorkingTime entity with many ManyToMany relation :

<?php

namespace App\Entity;

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

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

    /**
     * @ORM\ManyToMany(targetEntity=User::class, inversedBy="workingTimes")
     */
    private $user;

    /**
     * @ORM\ManyToMany(targetEntity=Customer::class, inversedBy="workingTimes")
     */
    private $customer;

    /**
     * @ORM\ManyToMany(targetEntity=Work::class, inversedBy="workingTimes")
     */
    private $work;

    /**
     * @ORM\ManyToMany(targetEntity=WorkingPlaceRelation::class, inversedBy="workingTimes")
     */
    private $workingPlace;

    /**
     * @ORM\Column(type="datetime")
     */
    private $createdAt;

    /**
     * @ORM\Column(type="integer")
     */
    private $totalTime;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $kmPerso;

    /**
     * @ORM\Column(type="boolean", nullable=true)
     */
    private $meal;

    public function __construct()
    {
        $this->user = new ArrayCollection();
        $this->customer = new ArrayCollection();
        $this->work = new ArrayCollection();
        $this->workingPlace = new ArrayCollection();
        $this->setCreatedAt(new \datetime);
    }

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

    /**
     * @return Collection|User[]
     */
    public function getUser(): Collection
    {
        return $this->user;
    }

    public function setUser(?User $user): self
    {
        $this->user = $user;

        return $this;
    }

    public function addUser(User $user): self
    {
        if (!$this->user->contains($user)) {
            $this->user[] = $user;
        }

        return $this;
    }

    public function removeUser(User $user): self
    {
        if ($this->user->contains($user)) {
            $this->user->removeElement($user);
        }

        return $this;
    }

    /**
     * @return Collection|Customer[]
     */
    public function getCustomer(): Collection
    {
        return $this->customer;
    }

    public function addCustomer(Customer $customer): self
    {
        if (!$this->customer->contains($customer)) {
            $this->customer[] = $customer;
        }

        return $this;
    }

    public function removeCustomer(Customer $customer): self
    {
        if ($this->customer->contains($customer)) {
            $this->customer->removeElement($customer);
        }

        return $this;
    }

    /**
     * @return Collection|Work[]
     */
    public function getWork(): Collection
    {
        return $this->work;
    }

    public function addWork(Work $work): self
    {
        if (!$this->work->contains($work)) {
            $this->work[] = $work;
        }

        return $this;
    }

    public function removeWork(Work $work): self
    {
        if ($this->work->contains($work)) {
            $this->work->removeElement($work);
        }

        return $this;
    }

    /**
     * @return Collection|WorkingPlaceRelation[]
     */
    public function getWorkingPlace(): Collection
    {
        return $this->workingPlace;
    }

    public function addWorkingPlace(WorkingPlaceRelation $workingPlace): self
    {
        if (!$this->workingPlace->contains($workingPlace)) {
            $this->workingPlace[] = $workingPlace;
        }

        return $this;
    }

    public function removeWorkingPlace(WorkingPlaceRelation $workingPlace): self
    {
        if ($this->workingPlace->contains($workingPlace)) {
            $this->workingPlace->removeElement($workingPlace);
        }

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->createdAt;
    }

    public function setCreatedAt(\DateTimeInterface $createdAt): self
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getTotalTime(): ?int
    {
        return $this->totalTime;
    }

    public function setTotalTime(?int $totalTime): self
    {
        $this->totalTime = $totalTime;

        return $this;
    }

    public function getKmPerso(): ?int
    {
        return $this->kmPerso;
    }

    public function setKmPerso(?int $kmPerso): self
    {
        $this->kmPerso = $kmPerso;

        return $this;
    }

    public function getMeal(): ?int
    {
        return $this->meal;
    }

    public function setMeal(?int $meal): self
    {
        $this->meal = $meal;

        return $this;
    }
}

I would like to create a custom query in the repository of this entity:

public function findByDate($date)
{
    return $this->createQueryBuilder('w')
        ->where('w.createdAt = :date')
        ->setParameter('date', $date)
        ->orderBy('w.customer.firstname', 'ASC')
        ->setMaxResults(10)
        ->getQuery()
        ->getResult()
    ;
}

But I get the following error:

[Semantical Error] line 0, col 85 near 'name ASC': Error: Class App\Entity\WorkingTime has no field or association named customer.firstname

you can see my customer Entity :

<?php

namespace App\Entity;

use App\Entity\Work;
use App\Repository\CustomerRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Constraints\Unique;

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

    /**
     * @ORM\Column(type="string", length=255)
     * @Assert\Regex(
     * pattern = "/^[0-9]{5}$/",
     * message = "Le numéro de client ne peut être qu'un chiffre")
     */
    private $customer_number;

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

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

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

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

    /**
     * @ORM\Column(type="integer")
     * @Assert\Regex(
     * pattern = "/^[0-9]{4}$/",
     * message = "Le code postal doit contenir 4 chiffres")
     */
    private $zip_code;

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

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

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

    /**
     * @ORM\Column(type="datetime")
     */
    private $created_at;

    /**
     * @ORM\Column(type="datetime")
     */
    private $updated_at;

    /**
     * @ORM\Column(type="smallint")
     */
    private $active;

    /**
     * @ORM\OneToMany(targetEntity=Work::class, mappedBy="customer", orphanRemoval=true)
     */
    private $works;

    /**
     * @ORM\ManyToMany(targetEntity=WorkingTime::class, mappedBy="customer")
     */
    private $workingTimes;


    public function __construct()
    {
        $this->works = new ArrayCollection();
        $this->setActive(1);
        $this->setCreatedAt(new \DateTime());
        $this->setUpdatedAt(new \DateTime());
        $this->workingTimes = new ArrayCollection();
    }

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

    public function getCustomerNumber(): ?string
    {
        return $this->customer_number;
    }

    public function setCustomerNumber(?string $customer_number): self
    {
        $this->customer_number = $customer_number;

        return $this;
    }

    public function getCompagnyName(): ?string
    {
        return $this->compagny_name;
    }

    public function setCompagnyName(?string $compagny_name): self
    {
        $this->compagny_name = $compagny_name;

        return $this;
    }

    public function getFirstname(): ?string
    {
        return $this->firstname;
    }

    public function setFirstname(?string $firstname): self
    {
        $this->firstname = $firstname;

        return $this;
    }

    public function getLastname(): ?string
    {
        return $this->lastname;
    }

    public function setLastname(?string $lastname): self
    {
        $this->lastname = $lastname;

        return $this;
    }

    public function getStreet(): ?string
    {
        return $this->street;
    }

    public function setStreet(?string $street): self
    {
        $this->street = $street;

        return $this;
    }

    public function getZipCode(): ?int
    {
        return $this->zip_code;
    }

    public function setZipCode(?int $zip_code): self
    {
        $this->zip_code = $zip_code;

        return $this;
    }

    public function getCity(): ?string
    {
        return $this->city;
    }

    public function setCity(?string $city): self
    {
        $this->city = $city;

        return $this;
    }

    public function getPhone(): ?string
    {
        return $this->phone;
    }

    public function setPhone(?string $phone): self
    {
        $this->phone = $phone;

        return $this;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(?string $email): self
    {
        $this->email = $email;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->created_at;
    }

    public function setCreatedAt(\DateTimeInterface $created_at): self
    {
        $this->created_at = $created_at;

        return $this;
    }

    public function getUpdatedAt(): ?\DateTimeInterface
    {
        return $this->updated_at;
    }

    public function setUpdatedAt(\DateTimeInterface $updated_at): self
    {
        $this->updated_at = $updated_at;

        return $this;
    }

    public function getActive(): ?int
    {
        return $this->active;
    }

    public function setActive(int $active): self
    {
        $this->active = $active;

        return $this;
    }

    /**
     * @return Collection|Work[]
     */
    public function getWorks(): Collection
    {
        return $this->works;
    }

    public function addWork(Work $work): self
    {
        if (!$this->works->contains($work)) {
            $this->works[] = $work;
            $work->setCustomer($this);
        }

        return $this;
    }

    public function removeWork(Work $work): self
    {
        if ($this->works->contains($work)) {
            $this->works->removeElement($work);
            // set the owning side to null (unless already changed)
            if ($work->getCustomer() === $this) {
                $work->setCustomer(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection|WorkingTime[]
     */
    public function getWorkingTimes(): Collection
    {
        return $this->workingTimes;
    }

    public function addWorkingTime(WorkingTime $workingTime): self
    {
        if (!$this->workingTimes->contains($workingTime)) {
            $this->workingTimes[] = $workingTime;
            $workingTime->addCustomer($this);
        }

        return $this;
    }

    public function removeWorkingTime(WorkingTime $workingTime): self
    {
        if ($this->workingTimes->contains($workingTime)) {
            $this->workingTimes->removeElement($workingTime);
            $workingTime->removeCustomer($this);
        }

        return $this;
    }

}

Solution

  • You need to join the customers like this:

    public function findByDate($date)
    {
        return $this->createQueryBuilder('w')
            ->join('w.customer', 'u')
            ->where('w.createdAt = :date')
            ->setParameter('date', $date)
            ->orderBy('u.firstname', 'ASC')
            ->setMaxResults(10)
            ->getQuery()
            ->getResult()
            ;
    }