I have two entity.
Book and Author
class Book
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private int $id;
/**
* #ORM\Column(type="string", length=255)
*/
private string $name;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Author", fetch="EXTRA_LAZY")
* #ORM\JoinTable(name="books_authors",
* joinColumns={#ORM\JoinColumn(name="book_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="author_id", referencedColumnName="id")}
* )
* #var PersistentCollection|ArrayCollection
*/
private $authors;
public function __construct()
{
$this->authors = 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 getAuthors()
{
return $this->authors;
}
public function setAuthors($authors)
{
$this->authors = $authors;
}
public function addAuthor($author){
if(!$this->authors->contains($author))
$this->authors->add($author);
}
public function removeAuthor($author){
if($this->authors->contains($author)){
$this->authors->removeElement($author);
}
}
}
In BookController i try create new book and use Serializer
book body like
{
"name:"book name",
"authors":[
1,
2
]
}
In controller
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$book = $this->serializer->deserialize($request->getContent(), Book::class, 'json');
try{
$this->entityManager->persist($book);
$this->entityManager->flush();
} catch (UniqueConstraintViolationException $exception){
return new JsonResponse('already exist', JsonResponse::HTTP_FOUND);
}
but on flush() I have exception:
Expected value of type "App\Entity\Author" for association field "App\Entity\Book#$authors", got "integer" instead.
because book->authors now is an id collection, but entity collection needle.
I have some variants of resolve this, but what is the best way for create and update entity?
You need to create EntityNormalizer like this:
[Medium post][1]
class EntityNormalizer extends ObjectNormalizer implements DenormalizableInterface
{
private $em;
public function __construct(EntityManagerInterface $em, ?ClassMetadataFactoryInterface $classMetadataFactory = null, ?NameConverterInterface $nameConverter = null, ?PropertyAccessorInterface $propertyAccessor = null, ?PropertyTypeExtractorInterface $propertyTypeExtractor = null)
{
$this->em = $em;
parent::__construct($classMetadataFactory, $nameConverter, $propertyAccessor, $propertyTypeExtractor);
}
public function supportsNormalization($data, $format = null)
{
return false;
}
public function supportsDenormalization($data, $type, $format = null)
{
return !$this->em->getMetadataFactory()->isTransient($type) && (is_string($data) || is_numeric($data));
}
public function denormalize($data, $class, $format = null, array $context = [])
{
return $this->em->find($class, $data);
}
}
[1]: https://medium.com/cloudstek/using-the-symfony-serializer-with-doctrine-relations-69ecb17e6ebd
Related
I'm triying to get a calculated value from database where this value depends on an external value. I got the next function:
public function findAllBy($search, $order, $limit, $offset) {
$qb = $this->entityManager
->createQueryBuilder()
->select('a, (ST_DISTANCE(ST_MakePoint(0,0), ST_MakePoint(0,0)) / 1000) as distance')
->from('App\Entity\App\Advertisement', 'a')
->setMaxResult($limit)
->setFirstResult($offset);
for ($order as $key => $value)
$qb->andWhere($key !== "distance" ? "a.{$key}" : "distance", $value);
return $qb->getQuery()->getResult();
}
This function works, but the problem comes now. Like I said, I need to modify two parameters, one of theme come from outside of this function, that's not a problem, the problem comes with the other one. I the advertisement table I got a column named "coordinate" of type Point (postgis), when I try to substitute one of ST_MakePoint like this:
(ST_DISTANCE(ST_MakePoint(a.coordinate[0] a.coordinate[1]), ST_MakePoint(0,0)) / 1000) as distance
I got the next error:
"[Syntax Error] line 0, col 49: Error: Expected Doctrine\\ORM\\Query\\Lexer::T_COMMA, got '['"
I also tried:
(ST_DISTANCE(a.coordinate::geometry, ST_MakePoint(0,0)) / 1000) as distance
"[Syntax Error] line 0, col 35: Error: Expected Doctrine\\ORM\\Query\\Lexer::T_COMMA, got ':'"
Other:
ERROR: function st_distance(point, geometry) does not exist
(ST_DISTANCE(a.coordinate, ST_MakePoint(0,0)) / 1000) as distance // Error coordinate not a geometry
Other:
[Syntax Error] line 0, col 54: Error: Expected Doctrine\\ORM\\Query\\Lexer::T_CLOSE_PARENTHESIS, got ':'"
(ST_DISTANCE(a.coordinate, ST_MakePoint(0,0)::point) / 1000) as distance
None of them works. I dont how can I use the coordinate column on DQL.
If that helps, I got another function that works, but it is SQL not DQL, and I dont know how to parse the result as entity. Here it is:
SELECT x.id
FROM (
SELECT
g.id,
(ST_DISTANCE(ST_MakePoint(g.coordinate[0], g.coordinate[1])::geography, ST_MakePoint($point)::geography) / 1000) as distance
FROM app.graveyard g
) AS x
WHERE x.distance <= 100
ORDER BY x.distance ASC
Entity:
<?php
namespace App\Entity\App;
use App\DBAL\Types\Geolocation\Point;
use App\Repository\App\AdvertisementRepository;
use App\Tools\Tools;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\MaxDepth;
/**
* #ORM\Entity(repositoryClass=AdvertisementRepository::class)
* #ORM\Table(schema="app")
*/
class Advertisement
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=App\Entity\App\Company::class, inversedBy="advertisements")
* #ORM\JoinColumn(nullable=false)
*/
private $company;
/**
* #ORM\Column(type="AdvertisementTypeEnum")
*/
private $type;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=500)
*/
private $description;
/**
* #ORM\Column(type="float")
*/
private $price;
/**
* #ORM\Column(type="integer")
*/
private $nicheTime;
/**
* #ORM\Column(type="boolean")
*/
private $enabled;
/**
* #ORM\OneToMany(targetEntity=App\Entity\App\AdvertisementComplement::class, mappedBy="advertisement")
*/
private $advertisementComplements;
/**
* #ORM\OneToMany(targetEntity=App\Entity\App\AdvertisementTransfer::class, mappedBy="advertisement")
*/
private $advertisementTransfers;
/**
* #ORM\OneToMany(targetEntity=App\Entity\App\AdvertisementGraveyard::class, mappedBy="advertisement")
*/
private $advertisementGraveyards;
/**
* #ORM\OneToMany(targetEntity=App\Entity\App\AdvertisementFuneralParlor::class, mappedBy="advertisement")
*/
private $advertisementFuneralParlors;
/**
* #ORM\OneToMany(targetEntity=AdvertisementCrematorium::class, mappedBy="advertisement")
*/
private $advertisementCrematoria;
/**
* #ORM\Column(type="integer")
*/
private $query;
/**
* #ORM\Column(type="datetime")
*/
private $createAt;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
/**
* #ORM\OneToMany(targetEntity=AdvertisementStatistic::class, mappedBy="advertisement")
*/
private $advertisementStatistics;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $publishDate;
/**
* #ORM\OneToMany(targetEntity=AdvertisementRate::class, mappedBy="advertisement")
*/
private $advertisementRates;
/**
* #ORM\Column(type="integer", options={"default":10000})
*/
private $version;
/**
* #ORM\OneToMany(targetEntity=Contract::class, mappedBy="advertisement", cascade={"persist"}, fetch="LAZY")
*/
private $contracts;
/**
* #ORM\Column(type="boolean")
*/
private $wake;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $wakeTime;
/**
* #ORM\Column(type="float", nullable=true)
*/
private $wakePrice;
/**
* #ORM\Column(type="float", nullable=true)
*/
private $kmExtraPrice;
/**
* #ORM\Column(type="boolean", nullable=true)
*/
private $wakeIncluded;
/**
* #ORM\Column(type="datetime_immutable", nullable=true)
*/
private $deletedAt;
/**
* #ORM\ManyToOne(targetEntity=City::class)
*/
private $city;
/**
* #ORM\Column(type="point", nullable=true)
*/
private $coordinate;
public function __construct()
{
$this->advertisementComplements = new ArrayCollection();
$this->advertisementTransfers = new ArrayCollection();
$this->advertisementGraveyards = new ArrayCollection();
$this->advertisementFuneralParlors = new ArrayCollection();
$this->advertisementCrematoria = new ArrayCollection();
$this->createAt = new \DateTime("now");
$this->updatedAt = new \DateTime("now");
$this->advertisementStatistics = new ArrayCollection();
$this->advertisementRates = new ArrayCollection();
$this->contracts = new ArrayCollection();
$this->coordinate = $this->city->getCoordinate();
}
public function getId(): ?int
{
return $this->id;
}
public function getCompany(): ?Company
{
return $this->company;
}
public function setCompany(?Company $company): self
{
$this->company = $company;
return $this;
}
public function getType()
{
return $this->type;
}
public function setType($type): self
{
$this->type = $type;
return $this;
}
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 getPrice(): ?float
{
return $this->price;
}
public function setPrice(float $price): self
{
$this->price = $price;
return $this;
}
public function getNicheTime(): ?int
{
return $this->nicheTime;
}
public function setNicheTime(?int $nicheTime): self
{
$this->nicheTime = $nicheTime;
return $this;
}
public function getEnabled(): ?bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): self
{
$this->enabled = $enabled;
return $this;
}
/**
* #return Collection|AdvertisementComplement[]|null
*/
public function getAdvertisementComplements(): ?Collection
{
return $this->advertisementComplements;
}
public function addAdvertisementComplement(AdvertisementComplement $advertisementComplement): self
{
if (!$this->advertisementComplements->contains($advertisementComplement)) {
$this->advertisementComplements[] = $advertisementComplement;
$advertisementComplement->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementComplement(AdvertisementComplement $advertisementComplement): self
{
if ($this->advertisementComplements->removeElement($advertisementComplement)) {
// set the owning side to null (unless already changed)
if ($advertisementComplement->getAdvertisement() === $this) {
$advertisementComplement->setAdvertisement(null);
}
}
return $this;
}
/**
* #return Collection|AdvertisementTransfer[]|null
*/
public function getAdvertisementTransfers(): ?Collection
{
return $this->advertisementTransfers;
}
public function addAdvertisementTransfer(AdvertisementTransfer $advertisementTransfer): self
{
if (!$this->advertisementTransfers->contains($advertisementTransfer)) {
$this->advertisementTransfers[] = $advertisementTransfer;
$advertisementTransfer->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementTransfer(AdvertisementTransfer $advertisementTransfer): self
{
if ($this->advertisementTransfers->removeElement($advertisementTransfer)) {
// set the owning side to null (unless already changed)
if ($advertisementTransfer->getAdvertisement() === $this) {
$advertisementTransfer->setAdvertisement(null);
}
}
return $this;
}
/**
* #return Collection|AdvertisementGraveyard[]
*/
public function getAdvertisementGraveyards(): Collection
{
return $this->advertisementGraveyards;
}
public function addAdvertisementGraveyard(AdvertisementGraveyard $advertisementGraveyard): self
{
if (!$this->advertisementGraveyards->contains($advertisementGraveyard)) {
$this->advertisementGraveyards[] = $advertisementGraveyard;
$advertisementGraveyard->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementGraveyard(AdvertisementGraveyard $advertisementGraveyard): self
{
if ($this->advertisementGraveyards->removeElement($advertisementGraveyard)) {
// set the owning side to null (unless already changed)
if ($advertisementGraveyard->getAdvertisement() === $this) {
$advertisementGraveyard->setAdvertisement(null);
}
}
return $this;
}
/**
* #return Collection|AdvertisementFuneralParlor[]
*/
public function getAdvertisementFuneralParlors(): Collection
{
return $this->advertisementFuneralParlors;
}
public function addAdvertisementFuneralParlor(AdvertisementFuneralParlor $advertisementFuneralParlor): self
{
if (!$this->advertisementFuneralParlors->contains($advertisementFuneralParlor)) {
$this->advertisementFuneralParlors[] = $advertisementFuneralParlor;
$advertisementFuneralParlor->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementFuneralParlor(AdvertisementFuneralParlor $advertisementFuneralParlor): self
{
if ($this->advertisementFuneralParlors->removeElement($advertisementFuneralParlor)) {
// set the owning side to null (unless already changed)
if ($advertisementFuneralParlor->getAdvertisement() === $this) {
$advertisementFuneralParlor->setAdvertisement(null);
}
}
return $this;
}
public function getQuery(): ?int
{
return $this->query;
}
public function setQuery(int $query): self
{
$this->query = $query;
return $this;
}
/**
* #return Collection|AdvertisementCrematorium[]
*/
public function getAdvertisementCrematoria(): Collection
{
return $this->advertisementCrematoria;
}
public function addAdvertisementCrematorium(AdvertisementCrematorium $advertisementCrematorium): self
{
if (!$this->advertisementCrematoria->contains($advertisementCrematorium)) {
$this->advertisementCrematoria[] = $advertisementCrematorium;
$advertisementCrematorium->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementCrematorium(AdvertisementCrematorium $advertisementCrematorium): self
{
if ($this->advertisementCrematoria->removeElement($advertisementCrematorium)) {
// set the owning side to null (unless already changed)
if ($advertisementCrematorium->getAdvertisement() === $this) {
$advertisementCrematorium->setAdvertisement(null);
}
}
return $this;
}
public function getCreateAt(): ?\DateTimeInterface
{
return $this->createAt;
}
public function getCreateAtNormalized(): string
{
return $this->createAt->format("Y-m-d H:i:s");
}
public function setCreateAt(): self
{
$this->createAt = new \DateTime("now");
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function getUpdateAtNormalized(): string
{
return $this->updatedAt->format("Y-m-d H:i:s");
}
public function setUpdatedAt(): self
{
$this->updatedAt = new \DateTime("now");
return $this;
}
/**
* #return Collection|AdvertisementStatistic[]
*/
public function getAdvertisementStatistics(): Collection
{
return $this->advertisementStatistics;
}
public function addAdvertisementStatistic(AdvertisementStatistic $advertisementStatistic): self
{
if (!$this->advertisementStatistics->contains($advertisementStatistic)) {
$this->advertisementStatistics[] = $advertisementStatistic;
$advertisementStatistic->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementStatistic(AdvertisementStatistic $advertisementStatistic): self
{
if ($this->advertisementStatistics->removeElement($advertisementStatistic)) {
// set the owning side to null (unless already changed)
if ($advertisementStatistic->getAdvertisement() === $this) {
$advertisementStatistic->setAdvertisement(null);
}
}
return $this;
}
public function getPublishDate(): ?\DateTimeInterface
{
return $this->publishDate;
}
public function setPublishDate(): self
{
$this->publishDate = new \DateTime("now");
return $this;
}
public function clearPublishDate(): self
{
$this->publishDate = null;
return $this;
}
/**
* #return Collection|AdvertisementRate[]
*/
public function getAdvertisementRates(): Collection
{
return $this->advertisementRates;
}
public function addAdvertisementRate(AdvertisementRate $advertisementRate): self
{
if (!$this->advertisementRates->contains($advertisementRate)) {
$this->advertisementRates[] = $advertisementRate;
$advertisementRate->setAdvertisement($this);
}
return $this;
}
public function removeAdvertisementRate(AdvertisementRate $advertisementRate): self
{
if ($this->advertisementRates->removeElement($advertisementRate)) {
// set the owning side to null (unless already changed)
if ($advertisementRate->getAdvertisement() === $this) {
$advertisementRate->setAdvertisement(null);
}
}
return $this;
}
public function getVersion(): int
{
return $this->version;
}
public function getStringVersion(): string
{
$v = $this->getVersion();
$result = "";
while ($v > 0) {
$result = ((strlen($result) + 2) % 3) == 0 ? '.' . $v %10 . $result : $v %10 . $result;
$v = (int)($v / 10);
}
return $result;
}
public function setVersion(int $version): self
{
$this->version = $version;
return $this;
}
/**
* #return Collection|Contract[]
*/
public function getContracts(): Collection
{
return $this->contracts;
}
public function addContract(Contract $contract): self
{
if (!$this->contracts->contains($contract)) {
$this->contracts[] = $contract;
$contract->setAdvertisement($this);
}
return $this;
}
public function removeContract(Contract $contract): self
{
if ($this->contracts->removeElement($contract)) {
// set the owning side to null (unless already changed)
if ($contract->getAdvertisement() === $this) {
$contract->setAdvertisement(null);
}
}
return $this;
}
public function getWake(): bool
{
return $this->wake;
}
public function setWake(bool $wake): self
{
$this->wake = $wake;
return $this;
}
public function getWakeTime(): ?int
{
return $this->wakeTime;
}
public function setWakeTime(?int $wakeTime): self
{
$this->wakeTime = $wakeTime;
return $this;
}
public function getWakePrice(): ?float
{
return $this->wakePrice;
}
public function setWakePrice(?float $wakePrice): self
{
$this->wakePrice = $wakePrice;
return $this;
}
public function getKmExtraPrice(): ?float
{
return $this->kmExtraPrice;
}
public function setKmExtraPrice(?float $kmExtraPrice): self
{
$this->kmExtraPrice = $kmExtraPrice;
return $this;
}
public function getWakeIncluded(): ?bool
{
return $this->wakeIncluded;
}
private function getJsonRates(): array
{
$size = sizeof($this->advertisementRates);
if ($size == 0) return [];
$average = 0.0;
$jsonRates = [];
foreach ($this->advertisementRates as $advertisementRate) {
array_push($jsonRates, $advertisementRate->toJsonArray());
$average += $advertisementRate->getScore();
}
$average /= $size;
return ["average" => $average, "rates" => $jsonRates, "size" => $size];
}
public function getDeletedAt(): ?\DateTimeImmutable
{
return $this->deletedAt;
}
public function setDeletedAt(?\DateTimeImmutable $deletedAt): self
{
$this->deletedAt = $deletedAt;
return $this;
}
public function setWakeIncluded(?bool $wakeIncluded): self
{
$this->wakeIncluded = $wakeIncluded;
return $this;
}
public function getCity(): ?City
{
return $this->city;
}
public function setCity(?City $city): self
{
$this->city = $city;
return $this;
}
public function getDistance(Point $destiny)
{
dump($this->tools);
return 0;
// return $this->tools->getDistanceBetweenPoint($this->coordinate, $destiny);
}
public function toJsonArray(): array
{
$publishDate = $this->getPublishDate();
$rates = $this->getJsonRates();
return [
"id" => $this->id,
"companyId" => $this->company->getId(),
"name" => $this->name,
"description" => $this->description,
"type" => $this->type,
"basePrice" => $this->price,
"query" => $this->query,
"updateAt" => $this->getUpdateAtNormalized(),
"publishDate" => !is_null($publishDate) ? $publishDate->format("d-m-Y") : null,
"enable" => $this->enabled,
"version" => $this->getStringVersion(),
"wake" => $this->wake,
"wakeIncluded" => $this->wakeIncluded,
"wakePrice" => $this->wakePrice,
"wakeTime" => $this->wakeTime,
"kmExtraPrice" => $this->kmExtraPrice,
"rates" => empty($rates) ?
null :
[
"average" => $rates['average'],
"rates" => $rates['rates'],
"ratesCount" => $rates['size']
],
];
}
}
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.
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 form that user can change it is own email. But when validation error occured or some constrait failed session die and user is redirected to login page. Important to note that user is authenticated by user and password from database. Thanks for helping
UPDATE
I just added User.php file for more details.
namespace App\Form;
class ChangeEmailType extends AbstractType
{
private $translator;
private $transformer;
public function __construct(TranslatorInterface $translator, DateTimeToStringTransformer $transformer)
{
$this->transformer = $transformer;
$this->translator = $translator;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('email', EmailType::class, array(
'required' => true,
'label' => $this->translator->trans('email'),
'attr' => array('class' => 'form-control')
))
->add('updationDate', HiddenType::class, array(
'required' => true,
'label' => false,
));
$builder->get('updationDate')->addModelTransformer($this>transformer);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'App\Entity\User',
'attr' => array('class' => 'change-email-form')
));
}
}
UserController.php
/**
* #Security("has_role('ROLE_USER')")
* #Route("/profile/change-email", name="change email")
*/
public function changeEmail(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(ChangeEmailType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
try
{
$this->entityManager->lock($this->getUser(), LockMode::OPTIMISTIC, $user->getUpdationDate());
$this->entityManager->flush();
$this->addFlash('success', $this->translator->trans('email_is_successfully_changed'));
return $this->redirectToRoute('dashboard');
}
catch (OptimisticLockException $exception)
{
$this->addFlash('success', $this->translator->trans('data_is_outdated_try_again'));
return $this->redirectToRoute('change email');
}
}
return $this->render('app/pages/profile/change-email.html.twig', array(
'form' => $form->createView()
));
}
User.php
namespace App\Entity;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
* #ORM\HasLifecycleCallbacks()
* #ORM\Table(name="users")
* #UniqueEntity(fields={"email"})
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #Assert\Length(
* min = 6,
* minMessage = "Password should by at least 6 characters long",
* groups={"registration"}
* )
* #Assert\Type(
* type="alnum",
* message="Password should contains only numbers and letters",
* groups={"registration"}
* )
* #Assert\NotBlank()
* #ORM\Column(type="text", nullable=true)
*/
private $password;
/**
* #Assert\NotBlank(message="field_is_required")
* #Assert\Email(message="email_is_invalid")
* #ORM\Column(type="string", length=255, unique=true)
*/
private $email;
/**
* #ORM\Column(type="string", length=255)
*/
private $theme;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $facebookId;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $linkedinId;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $passwordRecoveryHash;
/**
* #ORM\Column(type="integer")
*/
private $status;
/**
* #ORM\Column(type="string", length=255)
*/
private $emailConfirmationHash;
/**
* #ORM\Column(type="datetime")
* #ORM\Version
*/
private $updationDate;
/**
* #ORM\Column(type="datetime")
*/
private $creationDate;
/**
* #ORM\PrePersist()
*/
public function prePersist(): void
{
$this->creationDate = new DateTime();
$this->theme = 'light';
$this->status = 0;
}
public function getRoles()
{
return ['ROLE_USER'];
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return 'salt';
}
public function getUsername()
{
return $this->email;
}
public function eraseCredentials()
{
// TODO: Implement eraseCredentials() method.
}
public function getId()
{
return $this->id;
}
public function setId($id): void
{
$this->id = $id;
}
public function setPassword($password): void
{
$this->password = $password;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email): void
{
$this->email = $email;
}
public function getUpdationDate()
{
return $this->updationDate;
}
public function setUpdationDate($updationDate): void
{
$this->updationDate = $updationDate;
}
public function getCreationDate()
{
return $this->creationDate;
}
public function setCreationDate($creationDate): void
{
$this->creationDate = $creationDate;
}
public function getTheme()
{
return $this->theme;
}
public function setTheme($theme): void
{
$this->theme = $theme;
}
public function getPasswordRecoveryHash()
{
return $this->passwordRecoveryHash;
}
public function setPasswordRecoveryHash($passwordRecoveryHash): void
{
$this->passwordRecoveryHash = $passwordRecoveryHash;
}
public function getFacebookId()
{
return $this->facebookId;
}
public function setFacebookId($facebookId): void
{
$this->facebookId = $facebookId;
}
public function getLinkedinId()
{
return $this->linkedinId;
}
public function setLinkedinId($linkedinId): void
{
$this->linkedinId = $linkedinId;
}
public function getEmailConfirmationHash()
{
return $this->emailConfirmationHash;
}
public function setEmailConfirmationHash($emailConfirmationHash): void
{
$this->emailConfirmationHash = $emailConfirmationHash;
}
public function getStatus()
{
return $this->status;
}
public function setStatus($status): void
{
$this->status = $status;
}
}
So I had the same problem but I fixed it by to not passing object User to the formType.
This is my code
$user = $this->getUser();
// don't pass pass $user as parameter
$form = $this->createForm(ChangeEmailType::class);
$form->handleRequest($request);
if ($form->isSubmitted()) {
$em = $this->getDoctrine()->getManager();
$currentEmail = $user->getEmail();
$newEmail = $form->get('email')->getData();
$currentPassword = $form->get('currentPassword')->getData();
// verify if the tow emails are different
if ($currentEmail === $newEmail) {
$form->get('email')->addError(new FormError('You must choose a different email.'));
}
// verify if the email is used by another user
$userHasAlreadyThisEmail = $em->getRepository('App:User')->findOneBy(array('email' => $newEmail));
if ($userHasAlreadyThisEmail && $userHasAlreadyThisEmail !== $user) {
$form->get('email')->addError(new FormError('This email is already used.'));
}
// verify if the password is correct
$verify = $this->verify($currentPassword, $user->getPassword());
if ($verify === false) {
$form->get('currentPassword')->addError(new FormError('Incorrect password.'));
}
if ($form->isValid()) {
$this->addFlash('success', 'The email has been successfully modified.');
$user->setEmail($newEmail);
$em->flush();
return $this->redirectToRoute('profile_change_email');
}
}
public function verify($input, $existingHash)
{
$hash = password_verify($input, $existingHash);
return $hash === true;
}
I have a next tables: quiz, question and junction table question_quiz. I have a many-to-many relationship.
Insert is working for the tables quiz and questions but I don't understand how insert in junction table.
Entity quiz.
class Quiz
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=191)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Question", mappedBy="quiz", cascade={"persist"})
*/
private $questions;
public function __construct()
{
$this->questions = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* #return string|null
*/
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* #return Collection|Question[]
*/
public function getQuestions(): Collection
{
return $this->questions;
}
public function addQuestion(Question $question): self
{
if (!$this->questions->contains($question)) {
$this->questions[] = $question;
$question->addQuiz($this);
}
return $this;
}
public function removeQuestion(Question $question): self
{
if ($this->questions->contains($question)) {
$this->questions->removeElement($question);
$question->removeQuiz($this);
}
return $this;
}
}
Entity question.
class Question
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $title;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Quiz", inversedBy="questions")
*/
private $quiz;
public function __construct()
{
$this->quiz = 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;
}
/**
* #return Collection|Quiz[]
*/
public function getQuiz(): Collection
{
return $this->quiz;
}
public function addQuiz(Quiz $quiz): self
{
if (!$this->quiz->contains($quiz)) {
$this->quiz[] = $quiz;
}
return $this;
}
public function removeQuiz(Quiz $quiz): self
{
if ($this->quiz->contains($quiz)) {
$this->quiz->removeElement($quiz);
}
return $this;
}
}
Controller code:
$quiz = new Quiz();
$form = $this->get('form.factory')->createNamed('quiz', QuizType::class, $quiz);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($quiz);
$em->flush();
return $this->redirectToRoute('admin');
}
Code in controller is correct and working, but not working for a table of junction. Maybe need doing with join table, but I not sure it that is working for symfony 4. Could you help me, please?