I try to create a custom querybuilder with Symfony - php

I have a OneToMany relationship on these 2 entities:
Article
ArticleLikes
<?php
namespace App\Entity;
use App\Repository\ArticleRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ArticleRepository::class)
*/
class Article
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\Column(type="datetime_immutable")
*/
private $createdAt;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="articles")
* #ORM\JoinColumn(nullable=false)
*/
private $relation;
/**
* #ORM\OneToMany(targetEntity=ArticleLikes::class, mappedBy="article")
*/
private $articleLikes;
public function __construct()
{
$this->articleLikes = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeImmutable $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getRelation(): ?User
{
return $this->relation;
}
public function setRelation(?User $relation): self
{
$this->relation = $relation;
return $this;
}
/**
* #return Collection|ArticleLikes[]
*/
public function getArticleLikes(): Collection
{
return $this->articleLikes;
}
public function addArticleLike(ArticleLikes $articleLike): self
{
if (!$this->articleLikes->contains($articleLike)) {
$this->articleLikes[] = $articleLike;
$articleLike->setArticle($this);
}
return $this;
}
public function removeArticleLike(ArticleLikes $articleLike): self
{
if ($this->articleLikes->removeElement($articleLike)) {
// set the owning side to null (unless already changed)
if ($articleLike->getArticle() === $this) {
$articleLike->setArticle(null);
}
}
return $this;
}
/**
* #param User $user
* #return bool
*/
public function isLikedByUser(User $user): bool
{
foreach ($this->getArticleLikes() as $like)
{
if ($like->getUser() === $user) {
return true;
}
}
return false;
}
}
<?php
namespace App\Entity;
use App\Repository\ArticleLikesRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ArticleLikesRepository::class)
*/
class ArticleLikes
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=Article::class, inversedBy="articleLikes")
* #ORM\JoinColumn(nullable=false)
*/
private $article;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="articleLikes")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
* #ORM\Column(type="datetime_immutable")
*/
private $createdAt;
public function getId(): ?int
{
return $this->id;
}
public function getArticle(): ?Article
{
return $this->article;
}
public function setArticle(?Article $article): self
{
$this->article = $article;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeImmutable $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
}
The Article entity can contain a collection of ArticleLikes.
In the ArticleLikes entity, each like is related to an Article (articleId) as well as to a user field (userId).
To retrieve the number of likes for each article, I have a method in the Article entity:
/ **
* #return Collection | ArticleLikes []
* /
public function getArticleLikes (): Collection
{
return $ this-> articleLikes;
}
I am lost because I would like to create a query that allows you to retrieve the last 10 articles the most liked (with the most of ArticleLikes). I don't know if I need to do a left join or something else. How can I do this query?
I want to retrieve the 10 articles that have the most ArticleLikes.
Image:

The solution was to put:
->orderBy('count(al)', 'DESC')
Query Builder that gets the 10 most liked articles:
/**
* #return array
* get the 10 most liked articles
*/
public function findArticlesMostLiked(): array
{
return $this->createQueryBuilder('a')
->select( 'a')
->join('a.articleLikes', 'al')
->groupBy('al.article')
->orderBy('count(al)', 'DESC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}

Related

Symfony Delete an user with Foreign Key

I have a problem that i can't resolve. That's why i'm coming here.
On my website, an user can upload pictures and videos. When the user try to delete his account, he got a 500 error :
"SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails"
If i understood, i have to use "joinColumn" "onCascade" and "onDelete" (I want to keep the user's pictures and videos)
My User entity :
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
* #UniqueEntity(fields={"email"}, message="Cette adresse email est déjà utilisée.")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password;
/**
* #ORM\Column(type="boolean")
*/
private $isVerified = false;
/**
* #ORM\OneToMany(targetEntity=Picture::class, mappedBy="author")
*/
private $pictures;
/**
* #ORM\OneToMany(targetEntity=Video::class, mappedBy="author")
*/
private $videos;
/**
* #ORM\ManyToMany(targetEntity=Picture::class, mappedBy="fav")
*/
private $favoris;
/**
* #ORM\ManyToMany(targetEntity=Video::class, mappedBy="fav")
*/
private $fav;
public function __construct()
{
$this->pictures = new ArrayCollection();
$this->videos = new ArrayCollection();
$this->favoris = new ArrayCollection();
$this->fav = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* Returning a salt is only needed, if you are not using a modern
* hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
*
* #see UserInterface
*/
public function getSalt(): ?string
{
return null;
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function isVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): self
{
$this->isVerified = $isVerified;
return $this;
}
/**
* #return Collection|Picture[]
*/
public function getPictures(): Collection
{
return $this->pictures;
}
public function addPicture(Picture $picture): self
{
if (!$this->pictures->contains($picture)) {
$this->pictures[] = $picture;
$picture->setAuthor($this);
}
return $this;
}
public function removePicture(Picture $picture): self
{
if ($this->pictures->removeElement($picture)) {
// set the owning side to null (unless already changed)
if ($picture->getAuthor() === $this) {
$picture->setAuthor(null);
}
}
return $this;
}
/**
* #return Collection|Video[]
*/
public function getVideos(): Collection
{
return $this->videos;
}
public function addVideo(Video $video): self
{
if (!$this->videos->contains($video)) {
$this->videos[] = $video;
$video->setAuthor($this);
}
return $this;
}
public function removeVideo(Video $video): self
{
if ($this->videos->removeElement($video)) {
// set the owning side to null (unless already changed)
if ($video->getAuthor() === $this) {
$video->setAuthor(null);
}
}
return $this;
}
/**
* #return Collection|Picture[]
*/
public function getFavoris(): Collection
{
return $this->favoris;
}
public function addFavori(Picture $favori): self
{
if (!$this->favoris->contains($favori)) {
$this->favoris[] = $favori;
$favori->addFav($this);
}
return $this;
}
public function removeFavori(Picture $favori): self
{
if ($this->favoris->removeElement($favori)) {
$favori->removeFav($this);
}
return $this;
}
/**
* #return Collection|Video[]
*/
public function getFav(): Collection
{
return $this->fav;
}
public function addFav(Video $fav): self
{
if (!$this->fav->contains($fav)) {
$this->fav[] = $fav;
$fav->addFav($this);
}
return $this;
}
public function removeFav(Video $fav): self
{
if ($this->fav->removeElement($fav)) {
$fav->removeFav($this);
}
return $this;
}
}
My Picture entity :
<?php
namespace App\Entity;
use App\Repository\PictureRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #ORM\Entity(repositoryClass=PictureRepository::class)
*/
class Picture
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=150)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\Column(type="string", length=255, unique=true)
* #Gedmo\Slug(fields={"title"})
*/
private $slug;
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
/**
* #ORM\Column(type="datetime")
*/
private $publication_date;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="pictures")
* #ORM\JoinColumn(nullable=false)
*/
private $author;
/**
* #ORM\Column(type="string", length=150)
*/
private $category;
/**
* #ORM\Column(type="string", length=50)
*/
private $image;
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="favoris")
*/
private $fav;
public function __construct()
{
$this->fav = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
public function getPublicationDate(): ?\DateTimeInterface
{
return $this->publication_date;
}
public function setPublicationDate(\DateTimeInterface $publication_date): self
{
$this->publication_date = $publication_date;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
public function getCategory(): ?string
{
return $this->category;
}
public function setCategory(string $category): self
{
$this->category = $category;
return $this;
}
public function getImage(): ?string
{
return $this->image;
}
public function setImage(string $image): self
{
$this->image = $image;
return $this;
}
/**
* #return Collection|User[]
*/
public function getFav(): Collection
{
return $this->fav;
}
public function addFav(User $fav): self
{
if (!$this->fav->contains($fav)) {
$this->fav[] = $fav;
}
return $this;
}
public function removeFav(User $fav): self
{
$this->fav->removeElement($fav);
return $this;
}
}
My Video entity :
<?php
namespace App\Entity;
use App\Repository\VideoRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=VideoRepository::class)
*/
class Video
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=150)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\Column(type="datetime")
*/
private $publication_date;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="videos")
* #ORM\JoinColumn(nullable=false)
*/
private $author;
/**
* #ORM\Column(type="string", length=150)
*/
private $category;
/**
* #ORM\Column(type="string", length=50)
*/
private $vid;
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="fav")
*/
private $fav;
public function __construct()
{
$this->fav = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
public function getPublicationDate(): ?\DateTimeInterface
{
return $this->publication_date;
}
public function setPublicationDate(\DateTimeInterface $publication_date): self
{
$this->publication_date = $publication_date;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
public function getCategory(): ?string
{
return $this->category;
}
public function setCategory(string $category): self
{
$this->category = $category;
return $this;
}
public function getVid(): ?string
{
return $this->vid;
}
public function setVid(string $vid): self
{
$this->vid = $vid;
return $this;
}
/**
* #return Collection|User[]
*/
public function getFav(): Collection
{
return $this->fav;
}
public function addFav(User $fav): self
{
if (!$this->fav->contains($fav)) {
$this->fav[] = $fav;
}
return $this;
}
public function removeFav(User $fav): self
{
$this->fav->removeElement($fav);
return $this;
}
}
If you want to - when deleting a user - delete all his pictures and videos as well, you can just add cascade delete to the associations:
/**
* #ORM\OneToMany(targetEntity=Picture::class, mappedBy="author", cascade={"delete"})
*/
private $pictures;
/**
* #ORM\OneToMany(targetEntity=Video::class, mappedBy="author", cascade={"delete"})
*/
private $videos;
If you instead want to keep them and just remove the associoation to the user, add ON DELETE SET NULL to your author_id foreign keys in picture and video tables:
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="videos")
* #ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $author;
Then you have to assume in your code that $this->author can be null.

Symfony: $images must be an instance of Doctrine\Common\Collections\ArrayCollection, Doctrine\ORM\PersistentCollection used

I currently have the following error with my entity code, and I don't really understand why I am having this problem.
I only have it in the page of my create dashboard, while I don't call the images but only the heritages, and in the form everything works fine.
I have tried changing Collection to ArrayCollection but nothing has changed.
<?php
namespace App\Entity;
use App\Repository\PatrimoineRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity(repositoryClass=PatrimoineRepository::class)
*/
class Patrimoine
{
/**
* #ORM\Id
* #ORM\Column(type="string", unique=true)
* #ORM\GeneratedValue("UUID")
*/
private ?string $id = null;
/**
* #ORM\Column(type="string", length=255)
*/
private ?string $name;
/**
* #ORM\Column(type="string", length=255)
*/
private ?string $description;
/**
* #ORM\Column(type="json")
* #Assert\Collection(
* fields={
* "lat" = {
* #Assert\NotBlank,
* #Assert\Regex("/^(-?(?:1[0-7]|[1-9])?\d(?:\.\d{1,18})?|180(?:\.0{1,18})?)$/")
* },
* "lng" = {
* #Assert\NotBlank,
* #Assert\Regex("/^(-?[1-8]?\d(?:\.\d{1,18})?|90(?:\.0{1,18})?)$/")
* },
* },
* missingFieldsMessage="Le champs {{ field }} est manquant"
* )
*/
private array $localisation = [];
/**
* #ORM\Column(type="datetime_immutable")
*/
private ?\DateTimeImmutable $created_at;
/**
* #ORM\Column(type="string", length=255)
*/
private ?string $statut;
/**
* #ORM\ManyToOne(targetEntity=CategoryPatrimoine::class, inversedBy="patrimoines")
* #ORM\JoinColumn(nullable=false)
*/
private ?CategoryPatrimoine $category;
/**
* #ORM\Column(type="string", length=255)
*/
private ?string $visibility;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="patrimoines")
* #ORM\JoinColumn(nullable=false)
*/
private ?User $author;
/**
* #ORM\OneToMany(targetEntity=Image::class, mappedBy="patrimoine", orphanRemoval=true)
*/
private ArrayCollection $images;
public function __construct()
{
$this->setCreatedAt(new \DateTimeImmutable());
$this->images = new ArrayCollection();
}
public function getId(): ?string
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
public function getLocalisation(): ?array
{
return $this->localisation;
}
public function setLocalisation(array $localisation): self
{
$this->localisation = $localisation;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeImmutable $created_at): self
{
$this->created_at = $created_at;
return $this;
}
public function getStatut(): ?string
{
return $this->statut;
}
public function setStatut(string $statut): self
{
$this->statut = $statut;
return $this;
}
public function getCategory(): ?CategoryPatrimoine
{
return $this->category;
}
public function setCategory(?CategoryPatrimoine $category): self
{
$this->category = $category;
return $this;
}
public function getVisibility(): ?string
{
return $this->visibility;
}
public function setVisibility(string $visibility): self
{
$this->visibility = $visibility;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
/**
* #return Collection|Image[]
*/
public function getImages(): Collection
{
return $this->images;
}
public function addImage(Image $image): self
{
if (!$this->images->contains($image)) {
$this->images[] = $image;
$image->setPatrimoine($this);
}
return $this;
}
public function removeImage(Image $image): self
{
// set the owning side to null (unless already changed)
if ($this->images->removeElement($image) && $image->getPatrimoine() === $this) {
$image->setPatrimoine(null);
}
return $this;
}
}
I faced a similar problem too. You must declare the property as Collection (interface), not as implementation ArrayCollection because Doctrine ORM uses PersistentCollection when picks up data from database but you declare the property as ArrayCollection, and type mismatch happens.
class SomeEntity {
private Collection $items;
// all other code
}
I just realized that the typing of $ images was wrong, it was "ArrayCollection" whereas it must be "Collection"

Symfony 4.2 - Doctrine / schema:validate => The table with name 'fablab.appartment_user already exists

beginner here i'm trying to do an API with Api-platform and Symfony. Actually i want to create my database schema and start testing it but when using php bin/console doctrine:schema:validate, i got this error and i cant figure out how to fix it : The table with name 'mydb.appartment_user' already exists
Unfortunately i didnt found an answer on google to my problem :'(
Here is my appartement entity :
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\AppartmentRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Entity(repositoryClass=AppartmentRepository::class)
*/
class Appartment
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $adress;
/**
* #ORM\Column(type="string", length=255)
*/
private $latitude;
/**
* #ORM\Column(type="string", length=255)
*/
private $longitude;
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="occupied_appartments")
*/
private $current_tenant;
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="rented_appartments")
*/
private $landlord;
/**
* #ORM\OneToOne(targetEntity=Lock::class, cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $lock_id;
public function __construct()
{
$this->current_tenant = new ArrayCollection();
$this->landlord = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getAdress(): ?string
{
return $this->adress;
}
public function setAdress(string $adress): self
{
$this->adress = $adress;
return $this;
}
public function getLatitude(): ?string
{
return $this->latitude;
}
public function setLatitude(string $latitude): self
{
$this->latitude = $latitude;
return $this;
}
public function getLongitude(): ?string
{
return $this->longitude;
}
public function setLongitude(string $longitude): self
{
$this->longitude = $longitude;
return $this;
}
/**
* #return Collection|User[]
*/
public function getCurrentTenant(): Collection
{
return $this->current_tenant;
}
public function addCurrentTenant(User $currentTenant): self
{
if (!$this->current_tenant->contains($currentTenant)) {
$this->current_tenant[] = $currentTenant;
}
return $this;
}
public function removeCurrentTenant(User $currentTenant): self
{
$this->current_tenant->removeElement($currentTenant);
return $this;
}
/**
* #return Collection|User[]
*/
public function getLandlord(): Collection
{
return $this->landlord;
}
public function addLandlord(User $landlord): self
{
if (!$this->landlord->contains($landlord)) {
$this->landlord[] = $landlord;
}
return $this;
}
public function removeLandlord(User $landlord): self
{
$this->landlord->removeElement($landlord);
return $this;
}
public function getLockId(): ?Lock
{
return $this->lock_id;
}
public function setLockId(Lock $lock_id): self
{
$this->lock_id = $lock_id;
return $this;
}
}
and my user entity :
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
* #ORM\Table(name="`user`")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* #ORM\Column(type="json")
*/
private $roles = [];
/**
* #var string The hashed password
* #ORM\Column(type="string")
*/
private $password;
/**
* #ORM\Column(type="string", length=255)
*/
private $firstname;
/**
* #ORM\Column(type="string", length=255)
*/
private $lastname;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $profile_picture;
/**
* #ORM\ManyToMany(targetEntity=Appartment::class, mappedBy="current_tenant")
*/
private $occupied_appartments;
/**
* #ORM\ManyToMany(targetEntity=Appartment::class, mappedBy="landlord")
*/
private $rented_appartments;
/**
* #ORM\ManyToMany(targetEntity=Rental::class, mappedBy="tenant_id")
*/
private $tenant_rentals;
/**
* #ORM\ManyToMany(targetEntity=Rental::class, mappedBy="landlord_id")
*/
private $landlord_rentals;
public function __construct()
{
$this->occupied_appartments = new ArrayCollection();
$this->rented_appartments = new ArrayCollection();
$this->tenant_rentals = new ArrayCollection();
$this->landlord_rentals = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUsername(): string
{
return (string) $this->email;
}
/**
* #see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* #see UserInterface
*/
public function getPassword(): string
{
return (string) $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function getSalt()
{
// not needed when using the "bcrypt" algorithm in security.yaml
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
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 getProfilePicture(): ?string
{
return $this->profile_picture;
}
public function setProfilePicture(?string $profile_picture): self
{
$this->profile_picture = $profile_picture;
return $this;
}
/**
* #return Collection|Appartment[]
*/
public function getOccupiedAppartments(): Collection
{
return $this->occupied_appartments;
}
public function addOccupiedAppartment(Appartment $occupied_appartments): self
{
if (!$this->occupied_appartments->contains($occupied_appartments)) {
$this->occupied_appartments[] = $occupied_appartments;
$occupied_appartments->addCurrentTenant($this);
}
return $this;
}
public function removeOccupiedAppartment(Appartment $occupied_appartments): self
{
if ($this->occupied_appartments->removeElement($occupied_appartments)) {
$occupied_appartments->removeCurrentTenant($this);
}
return $this;
}
/**
* #return Collection|Appartment[]
*/
public function getRentedAppartments(): Collection
{
return $this->rented_appartments;
}
public function addRentedAppartment(Appartment $rentedAppartment): self
{
if (!$this->rented_appartments->contains($rentedAppartment)) {
$this->rented_appartments[] = $rentedAppartment;
$rentedAppartment->addLandlord($this);
}
return $this;
}
public function removeRentedAppartment(Appartment $rentedAppartment): self
{
if ($this->rented_appartments->removeElement($rentedAppartment)) {
$rentedAppartment->removeLandlord($this);
}
return $this;
}
/**
* #return Collection|Rental[]
*/
public function getTenantRentals(): Collection
{
return $this->tenant_rentals;
}
public function addTenantRental(Rental $tenantRental): self
{
if (!$this->tenant_rentals->contains($tenantRental)) {
$this->tenant_rentals[] = $tenantRental;
$tenantRental->addTenantId($this);
}
return $this;
}
public function removeTenantRental(Rental $tenantRental): self
{
if ($this->tenant_rentals->removeElement($tenantRental)) {
$tenantRental->removeTenantId($this);
}
return $this;
}
/**
* #return Collection|Rental[]
*/
public function getLandlordRentals(): Collection
{
return $this->landlord_rentals;
}
public function addLandlordRental(Rental $landlordRental): self
{
if (!$this->landlord_rentals->contains($landlordRental)) {
$this->landlord_rentals[] = $landlordRental;
$landlordRental->addLandlordId($this);
}
return $this;
}
public function removeLandlordRental(Rental $landlordRental): self
{
if ($this->landlord_rentals->removeElement($landlordRental)) {
$landlordRental->removeLandlordId($this);
}
return $this;
}
}
I tried to clear-cache and to force but it didnt work.
Thank's in advance for help and ask me if I forget any details !
add a JoinTable annotation for properties which have ManyToMany relation in Appartment entity
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="occupied_appartments")
* #ORM\JoinTable(name="appartment_current_tenant")
*/
private $current_tenant;
/**
* #ORM\ManyToMany(targetEntity=User::class, inversedBy="rented_appartments")
* #ORM\JoinTable(name="appartment_landlord")
*/
private $landlord;

Doctrine ManyToOne Relation not finding data with findBy method

I have a Article table that is allowed to have many comments.
And when i use findBy it does not find anything for that Article.
Here is my show Action.
$comments = $commentRepository->findBy(['article' => $article]);
dump($comments);die;
which just outputs-.
ArticleController.php on line 52:
[]
When i do findAll however i get 20 Results which look like this
$allComments = $commentRepository->findAll();
dump($allComments);die;
0 => Comment^ {#881 ▼
-id: 1
-authorName: "Author name here"
-content: "Here is the comment content"
-article: Article^ {#809 ▼
+__isInitialized__: false
-id: 117
-title: null
-slug: null
-content: null
-publishedAt: null
-author: null
-heartCount: 0
-imageFilename: null
-createdAt: null
-updatedAt: null
-comments: null
…2
}
Here is the complete showAction method
/**
* #Route("/news/{article}",
* name="article_show")
*
* #param Article $article
* #param SlackClient $slack
* #param EntityManagerInterface $entityManager
* #param CommentRepository $commentRepository
* #return \Symfony\Component\HttpFoundation\Response
* #throws \Http\Client\Exception
* #throws \Nexy\Slack\Exception\SlackApiException
*/
public function show( $article,
SlackClient $slack,
EntityManagerInterface $entityManager,
CommentRepository $commentRepository
)
{
$allComments = $commentRepository->findAll();
$comments = $commentRepository->findBy(['article' => $article]);
dump($allComments);die;
$repository = $entityManager->getRepository(Article::class);
/**
* #var Article $article
*/
$articleResult = $repository->findOneBy(['slug' => $article]);
if (!$articleResult) {
throw $this->createNotFoundException('No ' . $article . ' found');
}
Not sure if needed but here is my Article and Comment Entitiy just to make sure i have verything here.
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #ORM\Entity(repositoryClass="App\Repository\ArticleRepository")
*/
class Article
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #Gedmo\Slug(fields={"title"})
* #ORM\Column(type="string", length=100, unique=true)
*/
private $slug;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $content;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $publishedAt;
/**
* #ORM\Column(type="string", length=255)
*/
private $author;
/**
* #ORM\Column(type="integer")
*/
private $heartCount = 0;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $imageFilename;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="create")
*/
private $createdAt;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $updatedAt;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Comment", mappedBy="article")
*/
private $comments;
public function __construct()
{
$this->comments = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(?string $content): self
{
$this->content = $content;
return $this;
}
public function getPublishedAt(): ?\DateTimeInterface
{
return $this->publishedAt;
}
public function setPublishedAt(?\DateTimeInterface $publishedAt): self
{
$this->publishedAt = $publishedAt;
return $this;
}
public function getAuthor(): ?string
{
return $this->author;
}
public function setAuthor(string $author): self
{
$this->author = $author;
return $this;
}
public function getHeartCount(): ?int
{
return $this->heartCount;
}
public function setHeartCount(int $heartCount): self
{
$this->heartCount = $heartCount;
return $this;
}
public function getImageFilename(): ?string
{
return $this->imageFilename;
}
public function setImageFilename(?string $imageFilename): self
{
$this->imageFilename = $imageFilename;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* #return Collection|Comment[]
*/
public function getComments(): Collection
{
return $this->comments;
}
public function addComment(Comment $comment): self
{
if (!$this->comments->contains($comment)) {
$this->comments[] = $comment;
$comment->setArticle($this);
}
return $this;
}
public function removeComment(Comment $comment): self
{
if ($this->comments->contains($comment)) {
$this->comments->removeElement($comment);
// set the owning side to null (unless already changed)
if ($comment->getArticle() === $this) {
$comment->setArticle(null);
}
}
return $this;
}
}
and the Comments Entitiy.
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
/**
* #ORM\Entity(repositoryClass="App\Repository\CommentRepository")
*/
class Comment
{
use TimestampableEntity;
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $authorName;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Article", inversedBy="comments")
* #ORM\JoinColumn(nullable=false)
*/
private $article;
public function getId(): ?int
{
return $this->id;
}
public function getAuthorName(): ?string
{
return $this->authorName;
}
public function setAuthorName(string $authorName): self
{
$this->authorName = $authorName;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getArticle(): ?article
{
return $this->article;
}
public function setArticle(?article $article): self
{
$this->article = $article;
return $this;
}
}
Please let me know if you need any other information
The problem lies in showAction method.
You want to take a look at $article argument. Phpdoc says it will be instance of Article but it won't be.
Here:
$articleResult = $repository->findOneBy(['slug' => $article]);
You assume that $article contains string representing slug.
So you search for comments by article slug and comments don't contain this information. You want to fetch them by article id.

Ordering Tag entites by related Articles count

I want to fetch tags with their related articles. However the goal is to order them by count of related articles. How to achieve that using QueryBuilder and repositiry classes? I'm new to symfony and I've tried fetching tags by DQL but it was not fetching whole entities.
Tags and Articles are in #ManyToMany relation:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\ArticleRepository")
*/
class Article
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\Column(type="string", length=255)
*/
private $shortDescription;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\Column(type="float")
*/
private $price;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="articles")
*/
private $category;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Tag", inversedBy="articles")
*/
private $tags;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Author", inversedBy="articles")
*/
private $authors;
public function __construct()
{
$this->tags = new ArrayCollection();
$this->authors = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getShortDescription(): ?string
{
return $this->shortDescription;
}
public function setShortDescription(string $shortDescription): self
{
$this->shortDescription = $shortDescription;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getPrice(): ?float
{
return $this->price;
}
public function setPrice(float $price): self
{
$this->price = $price;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
/**
* #return Collection|Tag[]
*/
public function getTags(): Collection
{
return $this->tags;
}
public function addTag(Tag $tag): self
{
if (!$this->tags->contains($tag)) {
$this->tags[] = $tag;
}
return $this;
}
public function removeTag(Tag $tag): self
{
if ($this->tags->contains($tag)) {
$this->tags->removeElement($tag);
}
return $this;
}
/**
* #return Collection|Author[]
*/
public function getAuthors(): Collection
{
return $this->authors;
}
public function addAuthor(Author $author): self
{
if (!$this->authors->contains($author)) {
$this->authors[] = $author;
}
return $this;
}
public function removeAuthor(Author $author): self
{
if ($this->authors->contains($author)) {
$this->authors->removeElement($author);
}
return $this;
}
}
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\TagRepository")
*/
class Tag
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Article", mappedBy="tags")
*/
private $articles;
public function __construct()
{
$this->articles = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* #return Collection|Article[]
*/
public function getArticles(): Collection
{
return $this->articles;
}
public function addArticle(Article $article): self
{
if (!$this->articles->contains($article)) {
$this->articles[] = $article;
$article->addTag($this);
}
return $this;
}
public function removeArticle(Article $article): self
{
if ($this->articles->contains($article)) {
$this->articles->removeElement($article);
$article->removeTag($this);
}
return $this;
}
}
My last method I've used in TagRepository:
public function findTagsByArticlesCount()
{
return $this->createQueryBuilder('tag')
->leftJoin('tag.articles', 'article')
->orderBy('count(article.id)', 'DESC')
->getQuery()
->execute();
}
I vaguely recall a similar case I have 2 years ago, which I was able to resolve by having HIDDEN column:
public function findTagsByArticlesCount()
{
return $this->createQueryBuilder('tag')
->leftJoin('tag.articles', 'article')
->addSelect('COUNT(article.id) as HIDDEN cnt')
->orderBy('cnt', 'DESC')
->getQuery()
->execute();
}
However, I am currently not at my workstation to test this. Can you try it?
Hope it helps...
There is missing groupBy while counting tags in articles:
$this->createQueryBuilder('tag')
->leftJoin('tag.articles', 'article')
->addSelect('COUNT(tag.id) AS tagcount')
->groupBy('tag.id')
->orderBy('tagcount', 'DESC')
->getQuery()
->execute();
Note: while joining Articles you will receive number of tags * number of articles records that you need to group by tag to count number of tags in related articles.
Note 2: I would prefer to use innerJoin instead of leftJoin not choose tags without related articles.

Categories