I trie to get the documents stored with a message in the message_document table with a doctrine request but the request loops and ends up filling my memory
I tried the same request with sql on Dbeaver and it runs with no problem
great thanks for your help
My message.php
enter code here<?php
namespace App\Entity;
use DateTime;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\MessageRepository;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass=MessageRepository::class)
*/
class Message
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\ManyToOne(targetEntity=Conversation::class, inversedBy="messages")
*/
private $conversation;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="messages")
*/
private $user;
/**
* #ORM\OneToMany(targetEntity=MessageDocument::class, mappedBy="messages")
*/
private $messageDocuments;
public function __construct( string $content, User $user, Conversation $converstation) {
$this->content = $content;
$this->user = $user;
$this->conversation = $converstation;
$this->createdAt = new \DateTime('now');
$this->messageDocuments = new ArrayCollection();
}
public function getId():?int {
return $this->id;
}
public function getContent():?string {
return $this->content;
}
public function setContent(string $content):self {
$this->content = $content;
return $this;
}
public function getCreatedAt():?\DateTimeInterface {
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt):self {
$this->createdAt = $createdAt;
return $this;
}
public function getConversation():?Conversation
{
return $this->conversation;
}
public function setConversation(?Conversation $conversation):self {
$this->conversation = $conversation;
return $this;
}
public function getUser():?User {
return $this->user;
}
public function setUser(?User $user):self {
$this->user = $user;
return $this;
}
/**
* #return Collection|MessageDocument[]
*/
public function getMessageDocuments(): Collection
{
return $this->messageDocuments;
}
public function addMessageDocument(MessageDocument $messageDocument): self
{
if (!$this->messageDocuments->contains($messageDocument)) {
$this->messageDocuments[] = $messageDocument;
$messageDocument->setMessages($this);
}
return $this;
}
public function removeMessageDocument(MessageDocument $messageDocument): self
{
if ($this->messageDocuments->removeElement($messageDocument)) {
// set the owning side to null (unless already changed)
if ($messageDocument->getMessages() === $this) {
$messageDocument->setMessages(null);
}
}
return $this;
}
}
my MessageDocument.php
enter code here<?php
namespace App\Entity;
use App\Repository\MessageDocumentRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=MessageDocumentRepository::class)
*/
class MessageDocument
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $fileName;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $type;
/**
* #ORM\ManyToOne(targetEntity=Message::class, inversedBy="messageDocuments")
*/
private $message;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="messageDocuments")
*/
private $sender;
public function getId(): ?int
{
return $this->id;
}
public function getFileName(): ?string
{
return $this->fileName;
}
public function setFileName(string $fileName): self
{
$this->fileName = $fileName;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): self
{
$this->type = $type;
return $this;
}
public function getMessage(): ?Message
{
return $this->message;
}
public function setMessage(?Message $message): self
{
$this->message = $message;
return $this;
}
public function getSender(): ?User
{
return $this->sender;
}
public function setSender(?User $sender): self
{
$this->sender = $sender;
return $this;
}
}
the request on MessageDocument join Message
/**
* #return MessageDocument[] Returns an array of MessageDocument objects
*/
//$qb->expr()->eq('md.id = :val')
//,Join::WITH,$qb->expr()->eq('md.id = :val')
public function findDocByMessageId($messageId)
{
return $this->createQueryBuilder('md')
->select('md')
->join('md.message','m')
->where('m.id =:val')
->setParameter('val', $messageId)
->setMaxResults(20)
->getQuery()
->getResult();
}
the calling of the repo request
$allMessages = new ArrayCollection();
$docs=[];
foreach ($messages as $messageUnique) {
$messId = $messageUnique->getId();
$documentsMessages = $messageRepository->findDocByMessageId($messId);
if($documentsMessages !== null){
foreach($documentsMessages as $document){
$docs=$document;
}
//$messageUnique->addMessageDocument($document);
}
$conversation->setLastMessage($messageUnique);
$messageUnique = array(
'id' => $messageUnique->getId(),
'author' => $messageUnique->getUser()->getFullName(),
'authorId' => $messageUnique->getUser()->getId(),
'content' => $messageUnique->getContent(),
'createdAt' => $messageUnique->getCreatedAt()
);
$allMessages->add($messageUnique);
}
I finally solved the problem :)
I have used the #ignore decorator on two properties of the MessageDocument entity
I have changed my code and now error message is about circular reference
Message entity
<?php
namespace App\Entity;
use DateTime;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\MessageRepository;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass=MessageRepository::class)
*/
class Message
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\ManyToOne(targetEntity=Conversation::class, inversedBy="messages")
*/
private $conversation;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="messages")
*/
private $user;
/**
* #ORM\OneToMany(targetEntity=MessageDocument::class, mappedBy="message")
*/
private $messageDocument;
public function __construct( string $content, User $user, Conversation $converstation) {
$this->content = $content;
$this->user = $user;
$this->conversation = $converstation;
$this->createdAt = new \DateTime('now');
$this->messageDocuments = new ArrayCollection();
}
public function getId():?int {
return $this->id;
}
public function getContent():?string {
return $this->content;
}
public function setContent(string $content):self {
$this->content = $content;
return $this;
}
public function getCreatedAt():?\DateTimeInterface {
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt):self {
$this->createdAt = $createdAt;
return $this;
}
public function getConversation():?Conversation
{
return $this->conversation;
}
public function setConversation(?Conversation $conversation):self {
$this->conversation = $conversation;
return $this;
}
public function getUser():?User {
return $this->user;
}
public function setUser(?User $user):self {
$this->user = $user;
return $this;
}
/**
* #return Collection|MessageDocument[]
*/
public function getMessageDocument(): Collection
{
return $this->messageDocument;
}
public function addMessageDocument(MessageDocument $messageDocument): self
{
if (!$this->messageDocument->contains($messageDocument)) {
$this->messageDocument[] = $messageDocument;
$messageDocument->setMessages($this);
}
return $this;
}
public function removeMessageDocument(MessageDocument $messageDocument): self
{
if ($this->messageDocuments->removeElement($messageDocument)) {
// set the owning side to null (unless already changed)
if ($messageDocument->getMessages() === $this) {
$messageDocument->setMessages(null);
}
}
return $this;
}
}
MessageDocument entity
<?php
namespace App\Entity;
use App\Repository\MessageDocumentRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=MessageDocumentRepository::class)
*/
class MessageDocument
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $fileName;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $type;
/**
* #ORM\ManyToOne(targetEntity=Message::class, inversedBy="messageDocument")
*/
private $message;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="messageDocument")
*/
private $sender;
public function getId(): ?int
{
return $this->id;
}
public function getFileName(): ?string
{
return $this->fileName;
}
public function setFileName(string $fileName): self
{
$this->fileName = $fileName;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): self
{
$this->type = $type;
return $this;
}
public function getMessage(): ?Message
{
return $this->message;
}
public function setMessage(?Message $message): self
{
$this->message = $message;
return $this;
}
public function getSender(): ?User
{
return $this->sender;
}
public function setSender(?User $sender): self
{
$this->sender = $sender;
return $this;
}
}
js use to call controller from twig
function getMessages(conversationId , userId) {
superConversationId = conversationId;
userIdEnCours = userId;
//* On vide ce qu'il y avait avant
removeAllChildNodes(document.querySelector('.msg_history'));
//* On remet toutes les conversations en blanc
let allDivs = document.getElementsByClassName('chat_list');
for (let div of allDivs) {
div.style.background = '#f8f8f8';
}
//* background-color light-grey quand conversation selectionné
$("#"+ conversationId).css('background', "#e1e1e1")
let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
//si requête validé on traite la réponse
if (this.readyState == 4 && this.status == 200) {
let messages = JSON.parse(this.response);
let discussion = document.querySelector('.msg_history');
for (let message of messages) {
let dateMessage = new Date(message.createdAt)
var lastMessageId = message.id;
//* Affichage selon envoyé ou reçu
if (message.authorId == userIdEnCours) {
discussion.innerHTML += "<div class=\"outgoing_msg col-12 \"\><div class=\"sent_msg col-6 m-0\">"
+ "<p class='m-0'>" + message.content + "</p>"
+ "<span class=\"time_date\"> De " + message.author + " | " + dateMessage.toLocaleString() + "</span>"
+ "</div>"
;
} else {
discussion.innerHTML += "<div class=\"incoming_msg col-12 \">"
+ "<div class=\"received_msg col-12\"\><div class=\"received_withd_msg col-6\">"
+ "<p>" + message.content + "</p>"
+ "<span class=\"time_date_receiver\"> De " + message.author + " | " + dateMessage.toLocaleString() + "</span>"
+ "</div></div>"
;
}
}
//* scroll dernier message
let divMessagerie = document.querySelector(".msg_history");
divMessagerie.scrollTop = divMessagerie.scrollHeight;
//vl le 13/09
// ne voyant pas l'utilité ...
/* Interval = setInterval( () => {
$.ajax({
type: "POST",
url : "/checkMessage/" + lastMessageId,
success: function (response) {
if (response === true) {
clearInterval(Interval);
getMessages(
superConversationId,
userIdEnCours
);
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(errorThrown);
}
});
}, 5000); */
}
};
//! Ouverture de la requete (MOCK VERS PROD)
//* PROD
// xmlhttp.open("GET", "http://www.generation-boomerang.com/messagerie/conv/" + conversationId);
//* DEV
xmlhttp.open("GET", "/messagerie/conv/" + conversationId);
xmlhttp.send();
}
The controller to get the messages from a conversation
/**
* #Route("/messagerie/conv/{id}" , name="messagerie_getMessagesOfConv")
* #Security("is_granted('ROLE_ABONNE') or is_granted('ROLE_ADMIN')", message="Merci de vous abonner au portail pour bénéficier de cette super fonctionnalité !")
*/
public function getMessagesOfConv(int $id, EntityManagerInterface $entityManager, ConversationRepository $conversationRepository, ParticipantRepository $participantRepository,MessageDocumentRepository $messageRepository) {
//* Récup du user + check à faire
$userEncours = $this->getUser();
$userId = $userEncours->getId();
//* Ckeck si la conversation appartient bien au user
$check = $participantRepository->checkBelongs($id, $userId);
if ($check != 1) {
return $this->json('cette conv ne te regarde pas !');
}
$conversation = $conversationRepository->find($id);
$messages = $conversation->getMessages();
// $documentsMessages = new ArrayCollection();//vl
$allMessages = new ArrayCollection();
// $docs=;
foreach ($messages as $messageUnique) {
$messId = $messageUnique->getId();
$documentsMessages = $messageRepository->findDocByMessageId($messId);
if($documentsMessages !== null){
foreach($documentsMessages as $document){
// $docs=$document;
$messageUnique->addMessageDocument($document);
}
}
$conversation->setLastMessage($messageUnique);
$messageUnique = array(
'id' => $messageUnique->getId(),
'author' => $messageUnique->getUser()->getFullName(),
'authorId' => $messageUnique->getUser()->getId(),
'content' => $messageUnique->getContent(),
'createdAt' => $messageUnique->getCreatedAt(),
'messageDocuments'=>$messageUnique->getMessageDocument()
);
$allMessages->add($messageUnique);
}
$entityManager->persist($conversation);
$entityManager->flush();
//echo '<pre>'; var_dump( $conversation);exit;echo '</pre>';//
return $this->json($allMessages);
}
conversation entity
<?php
namespace App\Entity;
use App\Repository\ConversationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ConversationRepository::class)
*/
class Conversation {
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity=Message::class, cascade={"persist", "remove"})
*/
private $lastMessage;
/**
* #ORM\OneToMany(targetEntity=Message::class, mappedBy="conversation")
*/
private $messages;
/**
* #ORM\OneToMany(targetEntity="Participant", mappedBy="conversation")
*/
private $participants;
/**
* #ORM\Column(type="string" , length=50)
*/
private $title;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
public function __construct() {
$this->participants = new ArrayCollection();
$this->messages = new ArrayCollection();
$this->createdAt = new \DateTime('now');
}
public function getId():?int {
return $this->id;
}
public function getLastMessage():?Message {
return $this->lastMessage;
}
public function setLastMessage(?Message $lastMessage):self {
$this->lastMessage = $lastMessage;
return $this;
}
/**
* #return Collection|Message[]
*/
public function getMessages():Collection {
return $this->messages;
}
public function addMessage(Message $message):self {
if (!$this->messages->contains($message)) {
$this->messages[] = $message;
$message->setConversation($this);
}
return $this;
}
public function removeMessage(Message $message):self {
if ($this->messages->contains($message)) {
$this->messages->removeElement($message);
// set the owning side to null (unless already changed)
if ($message->getConversation() === $this) {
$message->setConversation(null);
}
}
return $this;
}
/**
* #return Collection|Participant[]
*/
public function getParticipants():Collection {
return $this->participants;
}
public function addParticipant(Participant $participant):self {
if (!$this->participants->contains($participant)) {
$this->participants[] = $participant;
$participant->setConversation($this);
}
return $this;
}
public function removeParticipant(Participant $participant):self {
if ($this->participants->contains($participant)) {
$this->participants->removeElement($participant);
// set the owning side to null (unless already changed)
if ($participant->getConversation() === $this) {
$participant->setConversation(null);
}
}
return $this;
}
/**
* Get the value of title
*/
public function getTitle() {
return $this->title;
}
/**
* Set the value of title
* #return self
*/
public function setTitle($title) {
$this->title = $title;
return $this;
}
public function getCreatedAt():?\DateTimeInterface {
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt):self {
$this->createdAt = $createdAt;
return $this;
}
}
and participant entity
<?php
namespace App\Entity;
use App\Repository\ParticipantRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ParticipantRepository::class)
*/
class Participant
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="participants")
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Conversation", inversedBy="participants")
*/
private $conversation;
private $messageReadAt;
/**
* Get the value of id
*/
public function getId()
{
return $this->id;
}
/**
* Get the value of user
*/
public function getUser()
{
return $this->user;
}
/**
* Set the value of user
*
* #return self
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* Get the value of conversation
*/
public function getConversation()
{
return $this->conversation;
}
/**
* Set the value of conversation
*
* #return self
*/
public function setConversation($conversation)
{
$this->conversation = $conversation;
return $this;
}
/**
* Get the value of messageReadAt
*/
public function getMessageReadAt()
{
return $this->messageReadAt;
}
/**
* Set the value of messageReadAt
*
* #return self
*/
public function setMessageReadAt($messageReadAt)
{
$this->messageReadAt = $messageReadAt;
return $this;
}
}
there is also a CreateMessageHandler and GetMessageHanler (but I don't understand how it works)
CreateMessageHandler
<?php
namespace App\MessageHandler;
use App\Entity\User;
use App\Entity\Message;
use App\Entity\Conversation;
use App\Message\CreateMessage;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class CreateMessageHandler implements MessageHandlerInterface
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager) {
$this->entityManager = $entityManager;
}
public function __invoke(CreateMessage $createMessage)
{
$conversation = $this->entityManager->getRepository(Conversation::class)->find($createMessage->getConversationId());
if(is_null($conversation))
{
$conversation = new Conversation();
$this->entityManager->persist($conversation);
$this->entityManager->flush();
} else {
$message = new Message(
$createMessage->getContent(),
$this->entityManager->getRepository(User::class)->find($createMessage->getUserId()),
$conversation,
);
// if ()
}
// Debug
// echo $createMessage->getContent();
// echo $message->getUser()->getId();
// echo $message->getConversation()->getId();
$this->entityManager->persist($message);
$this->entityManager->flush();
}
}
GetMessageHandler
<?php
namespace App\MessageHandler;
use App\Entity\Message;
use App\Message\GetMessages;
use App\Repository\MessageRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class GetMessagesHandler implements MessageHandlerInterface
{
private $entityManager;
private $messageRepository;
public function __construct(EntityManagerInterface $entityManager, MessageRepository $messageRepository) {
$this->entityManager = $entityManager;
}
public function __invoke(GetMessages $message)
{
//Récupérer les messages de la conversation
return $this->entityManager->getRepository(Message::class)->findBy(['conversation' => $message->getConversationId()]);
}
}
I think everything is there.
A little long sorry...
Hope somebody could find the reason why I have this circular reference
Thanks
I'm not sure at all about setting $messageUnique = array() with value of the same variable, you should probably use another name of variable. If you have an infinite loop problem it's coming from the PHP in your case.
Related
I'm fairly new to the Symfony universe, so please bear with me if this question has already been answered.
I have provided endpoints with the api-platform to create a RegistrationRequest. A RegistrationRequest has a user that is connected via a ManyToOne relation, so it is stored in another table. In the API, the user or user_id is read-only, this is why the user can not be set in the post data. If a RegistrationRequest is made via the API, the creation fails because the user_id is obviously null.
This is why I would like to set the user manually after a registration request is made via the API but before the RegistrationRequest is stored in the database.
The user is known via the global REMOTE_USER from where I can derive the corresponding user object.
src/Entity/RegistrationRequest.php:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=App\Repository\RegistrationRequestRepository::class)
* #ApiResource(
* normalizationContext={"groups" = {"read"}},
* denormalizationContext={"groups" = {"write"}},
* paginationEnabled=false,
* )
*/
class RegistrationRequest
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read"})
*/
private $id;
/**
* #ORM\Column(type="string", length=64, nullable=true)
* #Groups({"read", "write"})
*/
private $opt_email;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"read", "write"})
*/
private $title;
/**
* #Gedmo\Mapping\Annotation\Timestampable(on="create")
* #ORM\Column(type="datetime")
* #Groups({"read"})
*/
private $created_at;
/**
* #Gedmo\Mapping\Annotation\Timestampable(on="update")
* #ORM\Column(type="datetime")
* #Groups({"read"})
*/
private $updated_at;
/**
* #ORM\Column(type="text", nullable=true)
* #Groups({"read", "write"})
*/
private $notes;
/**
* #ORM\Column(type="string", length=16)
* #Groups({"read", "write"})
*/
private $language_code;
/**
* #ORM\Column(type="text")
* #Groups({"read", "write"})
*/
private $data;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="registrationRequests")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
public function getId(): ?int
{
return $this->id;
}
public function getOptEmail(): ?string
{
return $this->opt_email;
}
public function setOptEmail(?string $opt_email): self
{
$this->opt_email = $opt_email;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
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 getNotes(): ?string
{
return $this->notes;
}
public function setNotes(?string $notes): self
{
$this->notes = $notes;
return $this;
}
public function getLanguageCode(): ?string
{
return $this->language_code;
}
public function setLanguageCode(string $language_code): self
{
$this->language_code = $language_code;
return $this;
}
public function getData(): ?string
{
return $this->data;
}
public function setData(string $data): self
{
$this->data = $data;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
}
src/Controller/RegistrationRequestController.php:
<?php
namespace App\Controller;
use App\Service\IGSNService;
use App\Entity\RegistrationRequest;
use App\Form\RegistrationRequestType;
use App\Repository\RegistrationRequestRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* #Route("/registration_request")
*/
class RegistrationRequestController extends AbstractController
{
/**
* #Route("/")
*/
public function indexNoLocale(): Response
{
return $this->redirectToRoute('app_registration_request_index', ['_locale' => 'de']);
}
/**
* #Route("/{_locale<%app.supported_locales%>}/", name="app_registration_request_index", methods={"GET"})
*/
public function index(RegistrationRequestRepository $registrationRequestRepository): Response
{
return $this->render('registration_request/index.html.twig', [
'registration_requests' => $registrationRequestRepository->findAll(),
]);
}
/**
* #Route("/{_locale<%app.supported_locales%>}/new", name="app_registration_request_new", methods={"GET", "POST"})
*/
public function new(Request $request, RegistrationRequestRepository $registrationRequestRepository, IGSNService $igsnService, TranslatorInterface $translator): Response
{
$registrationRequest = new RegistrationRequest();
$form = $this->createForm(RegistrationRequestType::class, $registrationRequest);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$json_data = json_decode($registrationRequest->getData());
$err = $igsnService->validate_data($json_data);
if ($json_data !== null && empty($err)) {
$registrationRequestRepository->add($registrationRequest, true);
$this->addFlash(
'success',
$translator->trans('Your changes were saved!')
);
return $this->redirectToRoute('app_registration_request_index', [], Response::HTTP_SEE_OTHER);
} else {
$this->addFlash(
'schema_error',
$err
);
}
}
return $this->renderForm('registration_request/new.html.twig', [
'registration_request' => $registrationRequest,
'form' => $form,
]);
}
/**
* #Route("/{_locale<%app.supported_locales%>}/{id}", name="app_registration_request_show", methods={"GET"})
*/
public function show(RegistrationRequest $registrationRequest): Response
{
return $this->render('registration_request/show.html.twig', [
'registration_request' => $registrationRequest,
]);
}
/**
* #Route("/{_locale<%app.supported_locales%>}/{id}/edit", name="app_registration_request_edit", methods={"GET", "POST"})
*/
public function edit(Request $request, RegistrationRequest $registrationRequest, RegistrationRequestRepository $registrationRequestRepository, IGSNService $igsnService, TranslatorInterface $translator): Response
{
$form = $this->createForm(RegistrationRequestType::class, $registrationRequest);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$json_data = json_decode($registrationRequest->getData());
$err = $igsnService->validate_data($json_data);
if ($json_data !== null && empty($err)) {
$registrationRequestRepository->add($registrationRequest, true);
$this->addFlash(
'success',
$translator->trans('Your changes were saved!')
);
return $this->redirectToRoute('app_registration_request_index', [], Response::HTTP_SEE_OTHER);
} else {
$this->addFlash(
'schema_error',
$err
);
}
}
return $this->renderForm('registration_request/edit.html.twig', [
'registration_request' => $registrationRequest,
'form' => $form,
]);
}
/**
* #Route("/{_locale<%app.supported_locales%>}/{id}", name="app_registration_request_delete", methods={"POST"})
*/
public function delete(Request $request, RegistrationRequest $registrationRequest, RegistrationRequestRepository $registrationRequestRepository, TranslatorInterface $translator): Response
{
if ($this->isCsrfTokenValid('delete' . $registrationRequest->getId(), $request->request->get('_token'))) {
$registrationRequestRepository->remove($registrationRequest, true);
$this->addFlash(
'success',
$translator->trans('Request successfully deleted!')
);
}
return $this->redirectToRoute('app_registration_request_index', [], Response::HTTP_SEE_OTHER);
}
}
config/packages/api_platform.yaml
api_platform:
mapping:
paths: ['%kernel.project_dir%/src/Entity']
patch_formats:
json: ['application/merge-patch+json']
swagger:
versions: [3]
# Fixes empty api endpoint list with error:
# No operations defined in spec!
# See https://github.com/api-platform/core/issues/4485
metadata_backward_compatibility_layer: false
I have now got it solved with a DataPersister, as suggested by Julien B. in the comments.
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use App\Entity\RegistrationRequest;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
final class RequestDataPersister implements DataPersisterInterface
{
private $security;
public function __construct(Security $security, EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->security = $security;
}
public function supports($data): bool
{
return $data instanceof RegistrationRequest;
}
public function persist($data)
{
$data->setUser($this->security->getUser());
$this->entityManager->persist($data);
$this->entityManager->flush();
return $data;
}
public function remove($data): void
{
// no action needed
}
}
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.
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,
]);
}
I try to join two entities with Symfony QueryBuilder. I've created a function findAllQuery in order to filter a research, but I get the error that my entity doesn't have any association. I saw already some similar questions but I can't resolve the problem.
Thanks for help !
Publication entity
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=PublicationRepository::class)
*/
class Publication
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $datePublication;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="publications")
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity=Produit::class, inversedBy="publications")
*/
private $produit;
public function getId(): ?int
{
return $this->id;
}
public function getDatePublication(): ?\DateTimeInterface
{
return $this->datePublication;
}
public function setDatePublication(?\DateTimeInterface $datePublication): self
{
$this->datePublication = $datePublication;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getProduit(): ?Produit
{
return $this->produit;
}
public function setProduit(?Produit $produit): self
{
$this->produit = $produit;
return $this;
}
}
Produit Entity
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ProduitRepository::class)
*/
class Produit
{
public function hydrate(array $init)
{
foreach ($init as $key => $value) {
$method = "set" . ucfirst($key);
if (method_exists($this, $method)) {
$this->$method($value);
}
}
}
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $nom;
/**
* #ORM\Column(type="string", length=255)
*/
private $description;
/**
* #ORM\Column(type="boolean", nullable=true)
*/
private $vendu;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $photo;
/**
* #ORM\ManyToOne(targetEntity=Commande::class, inversedBy="produits")
*/
private $commande;
/**
* #ORM\ManyToOne(targetEntity=Type::class, inversedBy="produit")
*/
private $type;
/**
* #ORM\OneToOne(targetEntity=Publication::class, mappedBy="produit", cascade={"persist", "remove"})
*/
private $publication;
/**
* #ORM\Column(type="float")
*/
private $prix;
/**
* #ORM\OneToMany(targetEntity=Publication::class, mappedBy="produit")
*/
private $publications;
public function __construct()
{
$this->publications = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
public function getVendu(): ?bool
{
return $this->vendu;
}
public function setVendu(?bool $vendu): self
{
$this->vendu = $vendu;
return $this;
}
public function getPhoto(): ?string
{
return $this->photo;
}
public function setPhoto(?string $photo): self
{
$this->photo = $photo;
return $this;
}
public function getCommande(): ?Commande
{
return $this->commande;
}
public function setCommande(?Commande $commande): self
{
$this->commande = $commande;
return $this;
}
public function getType(): ?Type
{
return $this->type;
}
public function setType(?Type $type): self
{
$this->type = $type;
return $this;
}
public function getPrix(): ?float
{
return $this->prix;
}
public function setPrix(float $prix): self
{
$this->prix = $prix;
return $this;
}
/**
* #return Collection|Publication[]
*/
public function getPublications(): Collection
{
return $this->publications;
}
public function addPublication(Publication $publication): self
{
if (!$this->publications->contains($publication)) {
$this->publications[] = $publication;
$publication->setProduit($this);
}
return $this;
}
public function removePublication(Publication $publication): self
{
if ($this->publications->removeElement($publication)) {
// set the owning side to null (unless already changed)
if ($publication->getProduit() === $this) {
$publication->setProduit(null);
}
}
return $this;
}
}
Publication Repository
<?php
namespace App\Repository;
use App\Entity\Publication;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use App\Entity\ProduitSearch;
use App\Entity\Produit;
/**
* #method Publication|null find($id, $lockMode = null, $lockVersion = null)
* #method Publication|null findOneBy(array $criteria, array $orderBy = null)
* #method Publication[] findAll()
* #method Publication[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class PublicationRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Publication::class);
}
public function findAllQuery (ProduitSearch $search){
if ($search->getMaxPrix()){
return $this
->createQueryBuilder('publication')
->select('produit')
->from('App\Entity\Produit','produit')
->join('produit.prix','prix')
->andWhere('prix <= :maxPrix')
->setParameter('maxPrix', $search->getMaxPrix())
->getQuery()
->getResult();
}
return $this->findAll();
}
Your query is not right. You can only join on relations and not on fields. I guess you try to get publications where the price of any produit is lower than maxPrix.
return $this
->createQueryBuilder('publication')
->join('publication.produit','produit')
->andWhere('produit.prix <= :maxPrix')
->setParameter('maxPrix', $search->getMaxPrix())
->getQuery()
->getResult();
I have some entities, for example Device entity with a voter allowing the current user to access or not some Devices.
When searching for Devices, in order to filter, I user an array_filter function which is working well.
But, I want to make some stats on my Device entity, for example the number of Devices by Brand.
My Query is OK :
$query = $this->createQueryBuilder('d')
->select('COUNT(d.id), b.name')
->join('d.model', 'm')
->join('m.Brand', 'b')
->groupBy('b.name')
;
return $query->getQuery()->getResult();
I have an array with my datas.
But the voter doesn't apply.
If I switch the user to one who may not have access to all Devices, I still see the same numbers.
So, how can I filter my COUNT request with the voters ?
The Device Entity :
<?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\DeviceRepository")
*/
class Device
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=15)
*/
private $reference;
/**
* #ORM\Column(type="string", length=20)
*/
private $imei;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $buyDate;
/**
* #ORM\Column(type="float", nullable=true)
*/
private $buyPrice;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\DeviceGrade")
*/
private $grade;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\CustomerGroup")
* #ORM\JoinColumn(nullable=false)
*/
private $customerGroup;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\CustomerEntity")
*/
private $customerEntity;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\CustomerSite")
*/
private $customerSite;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Model")
* #ORM\JoinColumn(nullable=false)
*/
private $model;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $sellDate;
/**
* #ORM\Column(type="float", nullable=true)
*/
private $sellPrice;
/**
* #ORM\Column(type="datetime", nullable=true)
* #Gedmo\Timestampable(on="create")
*/
private $dateAdd;
/**
* #ORM\Column(type="datetime", nullable=true)
* #Gedmo\Timestampable(on="update")
*/
private $dateUpd;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #Gedmo\Blameable(on="create")
*/
private $createdBy;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #Gedmo\Blameable(on="update")
*/
private $modifiedBy;
/**
* #ORM\OneToMany(targetEntity="App\Entity\DeviceStatusHistory", mappedBy="device")
*/
private $deviceStatusHistories;
public function __construct()
{
$this->deviceStatusHistories = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getReference(): ?string
{
return $this->reference;
}
public function setReference(string $reference): self
{
$this->reference = $reference;
return $this;
}
public function getImei(): ?string
{
return $this->imei;
}
public function setImei(string $imei): self
{
$this->imei = $imei;
return $this;
}
public function getBuyDate(): ?\DateTimeInterface
{
return $this->buyDate;
}
public function setBuyDate(?\DateTimeInterface $buyDate): self
{
$this->buyDate = $buyDate;
return $this;
}
public function getBuyPrice(): ?float
{
return $this->buyPrice;
}
public function setBuyPrice(?float $buyPrice): self
{
$this->buyPrice = $buyPrice;
return $this;
}
public function getGrade(): ?DeviceGrade
{
return $this->grade;
}
public function setGrade(?DeviceGrade $grade): self
{
$this->grade = $grade;
return $this;
}
public function getCustomerGroup(): ?CustomerGroup
{
return $this->customerGroup;
}
public function setCustomerGroup(?CustomerGroup $customerGroup): self
{
$this->customerGroup = $customerGroup;
return $this;
}
public function getCustomerEntity(): ?CustomerEntity
{
return $this->customerEntity;
}
public function setCustomerEntity(?CustomerEntity $customerEntity): self
{
$this->customerEntity = $customerEntity;
return $this;
}
public function getCustomerSite(): ?CustomerSite
{
return $this->customerSite;
}
public function setCustomerSite(?CustomerSite $customerSite): self
{
$this->customerSite = $customerSite;
return $this;
}
public function getModel(): ?Model
{
return $this->model;
}
public function setModel(?Model $model): self
{
$this->model = $model;
return $this;
}
public function getSellDate(): ?\DateTimeInterface
{
return $this->sellDate;
}
public function setSellDate(?\DateTimeInterface $sellDate): self
{
$this->sellDate = $sellDate;
return $this;
}
public function getSellPrice(): ?float
{
return $this->sellPrice;
}
public function setSellPrice(?float $sellPrice): self
{
$this->sellPrice = $sellPrice;
return $this;
}
public function getDateAdd(): ?\DateTimeInterface
{
return $this->dateAdd;
}
public function setDateAdd(\DateTimeInterface $dateAdd): self
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpd(): ?\DateTimeInterface
{
return $this->dateUpd;
}
public function setDateUpd(\DateTimeInterface $dateUpd): self
{
$this->dateUpd = $dateUpd;
return $this;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
public function getModifiedBy(): ?User
{
return $this->modifiedBy;
}
public function setModifiedBy(?User $modifiedBy): self
{
$this->modifiedBy = $modifiedBy;
return $this;
}
/**
* #return Collection|DeviceStatusHistory[]
*/
public function getDeviceStatusHistories(): Collection
{
return $this->deviceStatusHistories;
}
public function addDeviceStatusHistory(DeviceStatusHistory $deviceStatusHistory): self
{
if (!$this->deviceStatusHistories->contains($deviceStatusHistory)) {
$this->deviceStatusHistories[] = $deviceStatusHistory;
$deviceStatusHistory->setDevice($this);
}
return $this;
}
public function removeDeviceStatusHistory(DeviceStatusHistory $deviceStatusHistory): self
{
if ($this->deviceStatusHistories->contains($deviceStatusHistory)) {
$this->deviceStatusHistories->removeElement($deviceStatusHistory);
// set the owning side to null (unless already changed)
if ($deviceStatusHistory->getDevice() === $this) {
$deviceStatusHistory->setDevice(null);
}
}
return $this;
}
public function __toString(): string
{
return $this->reference.' / '.$this->imei.' / '.$this->getModel()->getName().' - '.
$this->getModel()->getBrand()->getName().' - '.$this->getModel()->getColor()->getName().
' - '.$this->getModel()->getStorage()->getCapacity();
}
}
The Model Entity :
<?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;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\File;
/**
* #ORM\Entity(repositoryClass="App\Repository\ModelRepository")
* #Vich\Uploadable
*/
class Model
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="boolean")
*/
private $isActive;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $dateStartSell;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $dateEndSell;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $dateEndSupport;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Brand", inversedBy="models")
* #ORM\JoinColumn(nullable=false)
*/
private $Brand;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Color")
* #ORM\JoinColumn(nullable=false)
*/
private $color;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Storage")
*/
private $storage;
/**
* #ORM\Column(type="datetime", nullable=true)
* #Gedmo\Timestampable(on="create")
*/
private $dateAdd;
/**
* #ORM\Column(type="datetime", nullable=true)
* #Gedmo\Timestampable(on="update")
*/
private $dateUpd;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #Gedmo\Blameable(on="create")
*/
private $createdBy;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #Gedmo\Blameable(on="update")
*/
private $modifiedBy;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\CustomerGroup", inversedBy="models")
*/
private $customerGroup;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* #Vich\UploadableField(mapping="model_image", fileNameProperty="imageName", size="imageSize")
*
* #var File
*/
private $imageFile;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #var string
*/
private $imageName;
/**
* #ORM\Column(type="integer", nullable=true)
*
* #var integer
*/
private $imageSize;
public function __construct(?File $imageFile = null)
{
$this->customerGroup = new ArrayCollection();
$this->imageFile = $imageFile;
if (null !== $imageFile) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->dateUpd = new \DateTimeImmutable();
}
}
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;
}
public function getIsActive(): ?bool
{
return $this->isActive;
}
public function setIsActive(bool $isActive): self
{
$this->isActive = $isActive;
return $this;
}
public function getDateStartSell(): ?\DateTimeInterface
{
return $this->dateStartSell;
}
public function setDateStartSell(?\DateTimeInterface $dateStartSell): self
{
$this->dateStartSell = $dateStartSell;
return $this;
}
public function getDateEndSell(): ?\DateTimeInterface
{
return $this->dateEndSell;
}
public function setDateEndSell(?\DateTimeInterface $dateEndSell): self
{
$this->dateEndSell = $dateEndSell;
return $this;
}
public function getDateEndSupport(): ?\DateTimeInterface
{
return $this->dateEndSupport;
}
public function setDateEndSupport(?\DateTimeInterface $dateEndSupport): self
{
$this->dateEndSupport = $dateEndSupport;
return $this;
}
public function getBrand(): ?Brand
{
return $this->Brand;
}
public function setBrand(?Brand $Brand): self
{
$this->Brand = $Brand;
return $this;
}
public function getColor(): ?Color
{
return $this->color;
}
public function setColor(?Color $color): self
{
$this->color = $color;
return $this;
}
public function getStorage(): ?Storage
{
return $this->storage;
}
public function setStorage(?Storage $storage): self
{
$this->storage = $storage;
return $this;
}
public function getDateAdd(): ?\DateTimeInterface
{
return $this->dateAdd;
}
public function setDateAdd(\DateTimeInterface $dateAdd): self
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpd(): ?\DateTimeInterface
{
return $this->dateUpd;
}
public function setDateUpd(\DateTimeInterface $dateUpd): self
{
$this->dateUpd = $dateUpd;
return $this;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
public function getModifiedBy(): ?User
{
return $this->modifiedBy;
}
public function setModifiedBy(?User $modifiedBy): self
{
$this->modifiedBy = $modifiedBy;
return $this;
}
public function __toString(): string
{
return $this->getBrand()->getName().' '.$this->getName().' '.$this->getColor()->getName().' '.$this->getStorage()->getCapacity();
}
/**
* #return Collection|CustomerGroup[]
*/
public function getCustomerGroup(): Collection
{
return $this->customerGroup;
}
public function addCustomerGroup(CustomerGroup $customerGroup): self
{
if (!$this->customerGroup->contains($customerGroup)) {
$this->customerGroup[] = $customerGroup;
}
return $this;
}
public function removeCustomerGroup(CustomerGroup $customerGroup): self
{
if ($this->customerGroup->contains($customerGroup)) {
$this->customerGroup->removeElement($customerGroup);
}
return $this;
}
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* #param File|\Symfony\Component\HttpFoundation\File\UploadedFile $imageFile
*/
public function setImageFile(?File $imageFile = null): void
{
$this->imageFile = $imageFile;
if (null !== $imageFile) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->dateUpd = new \DateTimeImmutable();
}
}
public function getImageFile(): ?File
{
return $this->imageFile;
}
public function setImageName(?string $imageName): void
{
$this->imageName = $imageName;
}
public function getImageName(): ?string
{
return $this->imageName;
}
public function setImageSize(?int $imageSize): void
{
$this->imageSize = $imageSize;
}
public function getImageSize(): ?int
{
return $this->imageSize;
}
}
And the Brand Entity :
<?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\BrandRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Brand
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="create")
*/
private $dateAdd;
/**
* #ORM\Column(type="datetime")
* #Gedmo\Timestampable(on="create")
*/
private $dateUpd;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #ORM\JoinColumn(nullable=false)
* #Gedmo\Blameable(on="create")
*/
private $createdBy;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
* #ORM\JoinColumn(nullable=false)
* #Gedmo\Blameable(on="update")
*/
private $modifiedBy;
/**
* #ORM\Column(type="boolean")
*/
private $isDeleted;
/**
* #ORM\Column(type="boolean")
*/
private $isActive;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Model", mappedBy="Brand")
*/
private $models;
public function __construct()
{
$this->models = 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;
}
public function getDateAdd(): ?\DateTimeInterface
{
return $this->dateAdd;
}
public function setDateAdd(\DateTimeInterface $dateAdd): self
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpd(): ?\DateTimeInterface
{
return $this->dateUpd;
}
public function setDateUpd(\DateTimeInterface $dateUpd): self
{
$this->dateUpd = $dateUpd;
return $this;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
public function getModifiedBy(): ?User
{
return $this->modifiedBy;
}
public function setModifiedBy(?User $modifiedBy): self
{
$this->modifiedBy = $modifiedBy;
return $this;
}
public function getIsDeleted(): ?bool
{
return $this->isDeleted;
}
public function setIsDeleted(bool $isDeleted): self
{
$this->isDeleted = $isDeleted;
return $this;
}
public function getIsActive(): ?bool
{
return $this->isActive;
}
public function setIsActive(bool $isActive): self
{
$this->isActive = $isActive;
return $this;
}
/**
* #return Collection|Model[]
*/
public function getModels(): Collection
{
return $this->models;
}
public function addModel(Model $model): self
{
if (!$this->models->contains($model)) {
$this->models[] = $model;
$model->setBrand($this);
}
return $this;
}
public function removeModel(Model $model): self
{
if ($this->models->contains($model)) {
$this->models->removeElement($model);
// set the owning side to null (unless already changed)
if ($model->getBrand() === $this) {
$model->setBrand(null);
}
}
return $this;
}
}
Thanks for your help !
Best,
Julien
The voter won't update your query. It is used to check if a user is authorized to access some part of your code.
If you want to have your Devices according to your Voter, you'll need to write the correct query based on you need !
Thanks for your messages
#Alexandre : I'm going to search this way.
What I've done to achieve my goal :
- Add a bidirectionnal relation with inversedby in model and brand entities.
This way, I can make that :
$brands = $this->getDoctrine()->getRepository(Brand::class)->findAll();
$arrayBrands = array();
$arrayDevicesCount = array();
foreach($brands as $brand)
{
$devicesCount = 0;
$models = $brand->getModels();
foreach ($models as $model)
{
$devices = $model->getDevices()->getValues();
$devices = array_filter($devices, function (Device $device){
return $this->isGranted('view', $device);
});
$devicesCount+= count($devices);
}
if($devicesCount > 0)
{
array_push($arrayBrands, $brand->getName());
array_push($arrayDevicesCount, $devicesCount);
}
}
And this is working well !
I'm struggling for a while here. I need to display a table with some data. I've to get this data from different entities. I can't to get one value correctly as my join seems to break to correct data.
He is my Repository function :
$qb->select('j AS jou')
->innerJoin('j.playeds', 'p')
->addSelect('SUM(p.points) AS sumpoints')
->addSelect('SUM(p.max) AS summax')
->addSelect('COUNT(p.partie) as sumparties')
->addSelect('SUM(CASE WHEN p.position = 1 THEN 1 ELSE 0 END) AS sumwins')
->groupBy('j.id')
->orderBy('sumpoints', 'DESC')
->innerJoin('j.disputeds','d')
->addSelect('COUNT(d.id) AS nbDisputeds')
->addGroupBy('d.id');
At this point, everything works except this :
->addSelect('COUNT(d.id) AS nbDisputeds')
The data displayed is wrong probably because of my groupBy.
It should give me the number of "disputeds" occurences I have for each "j" but the result isn't correct.
Any help is welcome :)
Edit2: I tried from another repository but I get the same result, the problem is simply reported on other attributes :
$qb->select('d')
->innerJoin('d.joueur', 'j')
->addSelect('j.nom, j.prenom')
->addSelect('SUM(d.points) AS sumpoints')
->addSelect('COUNT(d) as sumparties')
->addSelect('SUM(CASE WHEN d.position = 1 THEN 1 ELSE 0 END) AS sumwins')
->GroupBy('d.joueur')
->leftJoin('j.playeds','p')
->addSelect('SUM(p.max) AS summax')
->addGroupBy('j.id')
->addGroupBy('p.partie');
In this case, I get correct values for sumpoints, sumparties, sumwins but summax gives me an incoherent value. That probably comes from a "bad" groupBy somewhere, i don't know..
Edit3 :
Works :
SELECT SUM(d0_.points) AS points, d0_.position AS position, j1_.nom AS nom, j1_.prenom AS prenom FROM disputed d0_ INNER JOIN joueur j1_ ON d0_.joueur_id = j1_.id GROUP BY d0_.joueur_id
But I don't have "max" value. Table "played" also is not joined
Doesn't Work :
SELECT SUM(d0_.points) AS points, j1_.nom AS nom, j1_.prenom AS prenom, SUM(p2_.max) AS maxs FROM disputed d0_ INNER JOIN joueur j1_ ON d0_.joueur_id = j1_.id INNER JOIN played p2_ ON j1_.id = p2_.joueur_id GROUP BY p2_.joueur_id
Table "played" is joined, "points" and "maxs" are not correct values
Database schema :
Entities :
Joueur Entity
<?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\JoueurRepository")
*/
class Joueur
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $nom;
/**
* #ORM\Column(type="string", length=100)
*/
private $prenom;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Disputed", mappedBy="joueur", orphanRemoval=true)
*/
private $disputeds;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Played", mappedBy="joueur")
*/
private $playeds;
public function __construct()
{
$this->disputeds = new ArrayCollection();
$this->playeds = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
public function getPrenom(): ?string
{
return $this->prenom;
}
public function setPrenom(string $prenom): self
{
$this->prenom = $prenom;
return $this;
}
/**
* #return Collection|Disputed[]
*/
public function getDisputeds(): Collection
{
return $this->disputeds;
}
public function addDisputed(Disputed $disputed): self
{
if (!$this->disputeds->contains($disputed)) {
$this->disputeds[] = $disputed;
$disputed->setJoueur($this);
}
return $this;
}
public function removeDisputed(Disputed $disputed): self
{
if ($this->disputeds->contains($disputed)) {
$this->disputeds->removeElement($disputed);
// set the owning side to null (unless already changed)
if ($disputed->getJoueur() === $this) {
$disputed->setJoueur(null);
}
}
return $this;
}
public function __toString()
{
$string = $this->getPrenom().' '.$this->getNom();
return $string;
}
/**
* #return Collection|Played[]
*/
public function getPlayeds(): Collection
{
return $this->playeds;
}
public function addPlayed(Played $played): self
{
if (!$this->playeds->contains($played)) {
$this->playeds[] = $played;
$played->setJoueur($this);
}
return $this;
}
public function removePlayed(Played $played): self
{
if ($this->playeds->contains($played)) {
$this->playeds->removeElement($played);
// set the owning side to null (unless already changed)
if ($played->getJoueur() === $this) {
$played->setJoueur(null);
}
}
return $this;
}
}
Disputed Entity
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\DisputedRepository")
*/
class Disputed
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $points;
/**
* #ORM\Column(type="integer")
*/
private $position;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Joueur", inversedBy="disputeds")
* #ORM\JoinColumn(nullable=false)
*/
private $joueur;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Tournoi", inversedBy="disputeds")
* #ORM\JoinColumn(nullable=false)
*/
private $tournament;
public function getId(): ?int
{
return $this->id;
}
public function getPoints(): ?int
{
return $this->points;
}
public function setPoints(int $points): self
{
$this->points = $points;
return $this;
}
public function getPosition(): ?int
{
return $this->position;
}
public function setPosition(int $position): self
{
$this->position = $position;
return $this;
}
public function getJoueur(): ?Joueur
{
return $this->joueur;
}
public function setJoueur(?Joueur $joueur): self
{
$this->joueur = $joueur;
return $this;
}
public function getTournament(): ?Tournoi
{
return $this->tournament;
}
public function setTournament(?Tournoi $tournament): self
{
$this->tournament = $tournament;
return $this;
}
}
Tournoi Entity
<?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\TournoiRepository")
*/
class Tournoi
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="date")
*/
private $date;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Disputed", mappedBy="tournament")
* #ORM\OrderBy({"points" = "DESC"})
*/
private $disputeds;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Partie", mappedBy="tournoi")
*/
private $Parties;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $nbPlayers;
public function __construct()
{
$this->disputeds = new ArrayCollection();
$this->parties = new ArrayCollection();
$this->Parties = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(\DateTimeInterface $date): self
{
$this->date = $date;
return $this;
}
/**
* #return Collection|Disputed[]
*/
public function getDisputeds(): Collection
{
return $this->disputeds;
}
public function addDisputed(Disputed $disputed): self
{
if (!$this->disputeds->contains($disputed)) {
$this->disputeds[] = $disputed;
$disputed->setTournament($this);
}
return $this;
}
public function removeDisputed(Disputed $disputed): self
{
if ($this->disputeds->contains($disputed)) {
$this->disputeds->removeElement($disputed);
// set the owning side to null (unless already changed)
if ($disputed->getTournament() === $this) {
$disputed->setTournament(null);
}
}
return $this;
}
/**
* #return Collection|Partie[]
*/
public function getParties(): Collection
{
return $this->parties;
}
public function addPartie(Partie $partie): self
{
if (!$this->parties->contains($partie)) {
$this->parties[] = $partie;
$partie->setTournoi($this);
}
return $this;
}
public function removePartie(Partie $partie): self
{
if ($this->parties->contains($partie)) {
$this->parties->removeElement($partie);
// set the owning side to null (unless already changed)
if ($partie->getTournoi() === $this) {
$partie->setTournoi(null);
}
}
return $this;
}
public function getNbPlayers(): ?int
{
return $this->nbPlayers;
}
public function setNbPlayers(?int $nbPlayers): self
{
$this->nbPlayers = $nbPlayers;
return $this;
}
public function addParty(Partie $party): self
{
if (!$this->Parties->contains($party)) {
$this->Parties[] = $party;
$party->setTournoi($this);
}
return $this;
}
public function removeParty(Partie $party): self
{
if ($this->Parties->contains($party)) {
$this->Parties->removeElement($party);
// set the owning side to null (unless already changed)
if ($party->getTournoi() === $this) {
$party->setTournoi(null);
}
}
return $this;
}
}