I have the following entity:
class DoctrinePartnerDao extends DoctrineBaseDao
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public int $id;
#[ORM\Column(type: 'uuid', unique: true, nullable: false)]
public Uuid $guid;
#[ORM\Column(type: 'string', length: 255, nullable: false)]
public string $name;
#[
ORM\ManyToOne(
targetEntity: DoctrineCountryDao::class,
cascade: ['persist']
)
]
public DoctrineCountryDao $country;
#[ORM\ManyToOne(targetEntity: DoctrineImageDao::class)]
#[ORM\JoinColumn(name: 'banner_image_id', nullable: true)]
public ?DoctrineImageDao $bannerImage = null;
#[ORM\ManyToOne(targetEntity: DoctrineImageDao::class)]
#[ORM\JoinColumn(name: 'avatar_image_id', nullable: true)]
public ?DoctrineImageDao $avatarImage = null;
#[ORM\Column(type: 'datetime', nullable: true)]
public ?DateTimeInterface $deletedAt;
And the save method:
public function save(Partner $partner): Partner
{
/** #var DoctrinePartnerDao */
$dao = $this->mapper->toDao($partner);
$countryId = $partner->getCountryId();
$countryReference = $this->getEntityManager()->getReference(
DoctrineCountryDao::class,
$countryId
);
if (!$countryReference) {
throw new InvalidAggregateIdException(
"Country with id '$countryId' does not exist."
);
}
$bannerImageReference = $partner->getBannerImageId()
? $this->getEntityManager()->getReference(
DoctrineImageDao::class,
$partner->getBannerImageId()
)
: null;
$avatarImageReference = $partner->getAvatarImageId()
? $this->getEntityManager()->getReference(
DoctrineImageDao::class,
$partner->getAvatarImageId()
)
: null;
$dao->country = $countryReference;
$dao->bannerImage = $bannerImageReference;
$dao->avatarImage = $avatarImageReference;
try {
$this->getEntityManager()
->persist($dao)
->flush();
} catch (Exception $e) {
dd($e);
}
return $partner;
}
Expected behavior: create the entity in db if it doesn't exist and if it exists update it. I am trying to avoid finding it first.
Before it was a 'merge' method but it seems it is deprecated now.
Getting the following error:
#message: "An exception occurred while executing a query: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'i\x03\xE4\xED\x18\xAE8\x18\xB6%\xD1\x18\xD7D\xE6\xBA' for key 'partner.UNIQ_312B3E162B6FCFB2'"
Related
I'm new on Symfony 6 and i've got problem with 2 of my entities.
App\Entity\Mission :
The mappings App\Entity\Mission#idtagmissionassign and App\Entity\Tag#missionstag are inconsistent with each other.
App\Entity\Tag :
The association App\Entity\Tag#missionstag refers to the inverse side field App\Entity\Mission#tags which does not exist.
This is the relation betewen the 2 entities :
DB
This is Mission entity
<?php
namespace App\Entity;
use App\Repository\MissionRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: MissionRepository::class)]
#[ORM\Table(name: 'mission')]
class Mission
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $titlemission = null;
#[ORM\Column(length: 255)]
private ?string $descriptionmission = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $onsetdate = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $deadline = null;
#[ORM\Column]
private ?int $budgetmission = null;
/*#[ORM\Column(length: 255)]
private ?string $codeapemission = null;*/
#[ORM\Column(length: 255)]
private ?string $prioritymission = null;
#[ORM\ManyToMany(targetEntity: Tag::class, inversedBy: 'missionstag',cascade: ['persist'])]
#[ORM\JoinTable(name:'mission_tag')]
private Collection $idtagmissionassign;
#[ORM\ManyToOne(inversedBy: 'missions')]
#[ORM\JoinColumn(nullable: false)]
private ?User $iduser = null;
#[ORM\ManyToMany(targetEntity: User::class, inversedBy: 'missionsassign')]
private Collection $idmissionassign;
#[ORM\Column(length: 100)]
private ?string $remote = null;
public function __construct()
{
$this->idtagmissionassign = new ArrayCollection();
$this->idmissionassign = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitlemission(): ?string
{
return $this->titlemission;
}
public function setTitlemission(string $titlemission): self
{
$this->titlemission = $titlemission;
return $this;
}
public function getDescriptionmission(): ?string
{
return $this->descriptionmission;
}
public function setDescriptionmission(string $descriptionmission): self
{
$this->descriptionmission = $descriptionmission;
return $this;
}
public function getOnsetdate(): ?\DateTimeInterface
{
return $this->onsetdate;
}
public function setOnsetdate(\DateTimeInterface $onsetdate): self
{
$this->onsetdate = $onsetdate;
return $this;
}
public function getDeadline(): ?\DateTimeInterface
{
return $this->deadline;
}
public function setDeadline(\DateTimeInterface $deadline): self
{
$this->deadline = $deadline;
return $this;
}
public function getBudgetmission(): ?int
{
return $this->budgetmission;
}
public function setBudgetmission(int $budgetmission): self
{
$this->budgetmission = $budgetmission;
return $this;
}
/*public function getCodeapemission(): ?string
{
return $this->codeapemission;
}
public function setCodeapemission(string $codeapemission): self
{
$this->codeapemission = $codeapemission;
return $this;
}*/
public function getPrioritymission(): ?string
{
return $this->prioritymission;
}
public function setPrioritymission(string $prioritymission): self
{
$this->prioritymission = $prioritymission;
return $this;
}
/**
* #return Collection<int, tag>
*/
public function getIdtagmissionassign(): Collection
{
return $this->idtagmissionassign;
}
public function addIdtagmissionassign(tag $idtagmissionassign): self
{
if (!$this->idtagmissionassign->contains($idtagmissionassign)) {
$this->idtagmissionassign->add($idtagmissionassign);
}
return $this;
}
public function removeIdtagmissionassign(tag $idtagmissionassign): self
{
$this->idtagmissionassign->removeElement($idtagmissionassign);
return $this;
}
public function getIduser(): ?user
{
return $this->iduser;
}
public function setIduser(?user $iduser): self
{
$this->iduser = $iduser;
return $this;
}
/**
* #return Collection<int, user>
*/
public function getIdmissionassign(): Collection
{
return $this->idmissionassign;
}
public function addIdmissionassign(user $idmissionassign): self
{
if (!$this->idmissionassign->contains($idmissionassign)) {
$this->idmissionassign->add($idmissionassign);
}
return $this;
}
public function removeIdmissionassign(user $idmissionassign): self
{
$this->idmissionassign->removeElement($idmissionassign);
return $this;
}
public function getRemote(): ?string
{
return $this->remote;
}
public function setRemote(string $remote): self
{
$this->remote = $remote;
return $this;
}
public function __toString(){
return $this->titlemission;
}
}
This is Tag entity :
<?php
namespace App\Entity;
use App\Repository\TagRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: TagRepository::class)]
class Tag
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 100)]
#[Assert\NotBlank]
#[Assert\Length(min:2)]
#[Assert\Valid]
private ?string $nomtag = null;
#[ORM\ManyToMany(targetEntity: Mission::class, mappedBy: 'tags')]
#[ORM\JoinTable(name:'mission_tag')]
private Collection $missionstag;
public function __construct()
{
$this->missionstag = new ArrayCollection();
}
// #[ORM\ManyToMany(targetEntity: Mission::class, inversedBy:"$idtagmissionassign")]
// private $genusScientists;
public function getId(): ?int
{
return $this->id;
}
public function getNomtag(): ?string
{
return $this->nomtag;
}
public function setNomtag(string $nomtag): self
{
$this->nomtag = $nomtag;
return $this;
}
/**
* #return Collection<int, Mission>
*/
public function getMissions(): Collection
{
return $this->missionstag;
}
public function addMission(Mission $mission): self
{
if (!$this->missionstag->contains($mission)) {
$this->missionstag->add($mission);
$mission->addTag($this);
}
return $this;
}
public function removeMission(Mission $mission): self
{
if ($this->missionstag->removeElement($mission)) {
$mission->removeTag($this);
}
return $this;
}
public function __toString(): string
{
return $this->nomtag;
}
}
Do you have an idea to help me to solve this problem ?
Many thanks
Change the mappedby and inversedby with no effect.
Trying some stuff follow internet guideline with no success.
Tag's property missionstag claims, that it is mapped by Missions's property "tags", but there is no such property, instead you have idtagmissionassign. (Side note: Your property names are bad, because they look like database columns, but you're using an ORM.
The first question you would have to ask yourself: will you need additional columns on your many-to-many table. If the answer is yes, ORM\ManyToMany isn't even the right fit. If the answer is no, it fits.
The case where it fits:
Mission should have the following property + attributes:
#[ORM\ManyToMany(targetEntity: Tag::class, inversedBy: 'missions', cascade: ['persist'])]
#[ORM\JoinTable(name: 'mission_tag')]
private Collection $tags;
and the Tag should have the following property + attributes:
#[ORM\ManyToMany(targetEntity: Mission::class, mappedBy: 'tags', cascade: ['persist'])]
#[ORM\JoinTable(name: 'mission_tag')] // <- is this the actual table name?
private Collection $missions;
the mappedBy and inversedBy must match the property name on the other entity, respectively.
If your mission_tag table doesn't have columns mission_id and tag_id, you might have to explicitly name the columns via the JoinColumn and InverseJoinColumn Attibutes.
For the case, where it doesn't fit, you would have to have an actual entity MissionTags with OneToMany on Mission/Tag that both reference it, and reversed ManyToOnes on MissionTags. But that wasn't what you asked.
BC\InventoryBundle\Entity\ProductRecipe:
type: entity
table: ProductRecipe
repositoryClass: BC\InventoryBundle\Entity\ProductRecipeRepository
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
amount: // Previously "ammount"
type: decimal
presision: 10
scale: 2
manyToOne:
products:
targetEntity: Product
// "Products" is named correctly but recipe is singular
// so for the sake of uniformity
inversedBy: recipes
joinColumn:
name: product_id
referencedColumnName: id
recipes:
targetEntity: Recipe
// Previously "Recipes", incorrect entity name
inversedBy: products
joinColumn:
name: recipe_id
referencedColumnName: id
I'm trying to create a blog with symfony and I'm new in this field, I can’t solve the error that appears to me and I don’t understand where it comes from:
An exception occurred while executing a query:
SQLSTATE\[23000\]: Integrity constraint violation: 19 NOT NULL constraint failed: articles.users_id
Articles.php
#[ORM\Entity(repositoryClass: ArticlesRepository::class)]
class Articles implements TimestampedInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(type: 'string', length: 255)]
private $titre;
#[ORM\Column(type: 'string', length: 255)]
#[Groups('article')]
private $slug;
#[ORM\Column(type: 'text')]
private $contenu;
#[ORM\Column(type: 'datetime')]
#[Groups('article')]
private $created_at;
#[ORM\Column(type: 'datetime', nullable: true)]
private $updated_at;
#[ORM\ManyToOne(targetEntity: Users::class, inversedBy: 'articles')]
#[ORM\JoinColumn(nullable: false)]
private $users;
#[ORM\OneToMany(mappedBy: 'articles', targetEntity: Commentaires::class, orphanRemoval: true)]
private $commentaires;
#[ORM\ManyToMany(targetEntity: MotsCles::class, inversedBy: 'articles')]
private $mots_cles;
#[ORM\ManyToMany(targetEntity: Categories::class, inversedBy: 'articles')]
private $categories;
public function __construct()
{
$this->commentaires = new ArrayCollection();
$this->mots_cles = new ArrayCollection();
$this->categories = new ArrayCollection();
}
public function getId() : ?int
{
return $this->id;
}
}
ArticlesCrudController.php
class ArticlesCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Articles::class;
}
public function configureFields(string $pageName): iterable
{
yield IdField::new('id');
yield TextField::new('titre');
yield TextEditorField::new('contenu');
yield DateTimeField::new('created_at')->hideOnForm();
yield DateTimeField::new('updated_at')->hideOnForm();
}
}
DashBoardController.php
class DashboardController extends AbstractDashboardController
{ public function __construct(private AdminUrlGenerator $adminUrlGenerator){
}
#[Route('/admin', name: 'admin')]
public function index(): Response
{
$url = $this->adminUrlGenerator->setController(ArticlesCrudController::class)->generateUrl();
return $this->redirect($url);
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('BLOG DE HIBA');
}
public function configureMenuItems(): iterable
{
yield MenuItem::linkToDashboard('Dashboard', '');
yield MenuItem::subMenu('Articles', '')->setSubItems([
MenuItem::linkToCrud('Tous les articles' , 'fas fa-book',Articles::class),
MenuItem::linkToCrud('Ajouter' , 'fas fa-plus',Articles::class)->setAction(Crud::PAGE_NEW),
MenuItem::linkToCrud('Categories' , 'fas fa-tag',Categories::class),
MenuItem::linkToCrud('MotsCles' , 'fas fa-tag',MotsCles::class)
]);
yield MenuItem::subMenu('Utilisateurs', '')->setSubItems([
MenuItem::linkToCrud('Utilisateurs' , 'fas fa-user',Users::class),
]);
}
}
Please I need Help, any suggestion would be great!!!
An exception occurred while executing a query:
SQLSTATE\[23000\]: Integrity constraint violation: 19 NOT NULL constraint failed: articles.users_id
How do you declare joinColumns/composite keys with PHP attributes. Haven't been able to find the right way and it is not documented (https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/reference/attributes-reference.html)
Entities
Comment.php
#[ORM\Entity(repositoryClass: CommentRepository::class)]
class Comment
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\ManyToOne(targetEntity: PullRequest::class, inversedBy: 'comments')]
#[ORM\JoinColumn(name: 'pull_request_id', referencedColumnName: 'id')]
#[ORM\JoinColumn(name: 'repo_id', referencedColumnName: 'repo_id')]
private $pullRequest;
}
PullRequest.php
#[ORM\Entity(repositoryClass: PullRequestRepository::class)]
class PullRequest
{
#[ORM\Id]
#[ORM\Column(type: 'integer', unique: false)]
private $id;
#[ORM\Id]
#[ORM\ManyToOne(targetEntity: Repo::class, inversedBy: 'pullRequests')]
#[ORM\JoinColumn(nullable: false)]
private $repo;
#[ORM\OneToMany(mappedBy: 'pullRequest', targetEntity: Comment::class, orphanRemoval: true)]
private $comments;
}
I ran into the same issue today and managed to find a workaround. It indeed seems like JoinColumns is not available as a PHP8 attribute, at least not at Doctrine ORM 2.11 nor the upcoming 2.12 / 3.0.
However, you can work around this by moving the join columns definitions into an AssociationsOverride attribute at the class level as follows:
#[ORM\Entity(repositoryClass: CommentRepository::class)]
#[ORM\AssociationOverrides([
new ORM\AssociationOverride(
name: 'pullRequest',
joinColumns: [
new ORM\JoinColumn(name: 'pull_request_id', referencedColumnName: 'id'),
new ORM\JoinColumn(name: 'repo_id', referencedColumnName: 'repo_id')
]
)
])]
class Comment
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\ManyToOne(targetEntity: PullRequest::class, inversedBy: 'comments')]
private $pullRequest;
}
According to https://github.com/greg0ire/doctrine-orm/commit/18366db5789b03e1d8a34933fbbff97a768a9cfe the "JoinColumns" attribute is no longer required, multiple "JoinColumn" attributes are sufficient.
I've got a 3 entities and I would like to get property from entity 1 to entity 3. Let me explain with my classes :
class City
{
#[ORM\Column(type: 'string', length: 255)]
#[Assert\NotBlank]
#[Assert\Length(min: 1)]
private string $name;
#[ORM\Column(type: 'string', length: 20)]
#[Assert\NotBlank]
private string $code;
#[ORM\OneToOne(targetEntity: CityHomePage::class, cascade: ['persist', 'remove'])]
private CityHomePage $homePage;
public function getHomePage(): CityHomePage
{
return $this->homePage;
}
public function setHomePage(CityHomePage $homePage): self
{
$this->homePage = $homePage;
return $this;
}
}
class CityHomePage
{
#[ORM\OneToOne(targetEntity: City::class, cascade: ['persist', 'remove'])]
#[ORM\JoinColumn(nullable: false)]
private City $city;
#[ORM\ManyToOne(targetEntity: Page::class, inversedBy: 'cityHomePages')]
#[ORM\JoinColumn(nullable: false)]
private Page $page;
#[ORM\OneToOne(targetEntity: Image::class, cascade: ['persist', 'remove'])]
private Image $image;
public function getCity(): ?City
{
return $this->city;
}
public function setCity(City $city): self
{
$this->city = $city;
return $this;
}
public function getPage(): ?Page
{
return $this->page;
}
public function setPage(?Page $page): self
{
$this->page = $page;
return $this;
}
public function getImage(): Image
{
return $this->image;
}
public function setImage(Image $image): self
{
$this->image = $image;
return $this;
}
}
class Page
{
#[ORM\Column(type: 'string', length: 100)]
#[Assert\Length(min: 1)]
private string $title;
/** #var Collection<int, CityHomePage> */
#[ORM\OneToMany(mappedBy: 'page', targetEntity: CityHomePage::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
private Collection $cityHomePages;
public function __construct()
{
parent::__construct();
$this->cityHomePages = new ArrayCollection();
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
/**
* #return Collection<int, CityHomePage>
*/
public function getCityHomePages(): Collection
{
return $this->cityHomePages;
}
public function addCityHomePage(CityHomePage $cityHomePage): self
{
if (!$this->cityHomePage->contains($cityHomePage)) {
$this->cityHomePage[] = $cityHomePage;
$cityHomePage->setPage($this);
}
return $this;
}
public function removeCityHomePage(CityHomePage $cityHomePage): self
{
if ($this->cityHomePage->removeElement($cityHomePage) && $cityHomePage->getPage() === $this) {
$cityHomePage->setPage(null);
}
return $this;
}
}
I created a CityCrudController and in my configurationField I add :
public function configureFields(string $pageName): iterable
{
return [
TextField::new('name',$this->translator->trans('EA.name'))->onlyOnIndex(),
TextField::new('code')->onlyOnIndex(),
AssociationField::new('homePage', $this->translator->trans('EA.image'))->onlyWhenUpdating(),
];
}
This is work but now I need to access from my CityCrudController the property 'title' from the Entity Page.
Is it a way to cross multiple entity to get what I need ?
Ok I found it => 'city.page.title'
first of all, i'm sorry if that double post but I don't found any ressource with this issue or exemple that fix it and i don't understand what's going in his head.
I'm in Symfony/Doctrine and Vue/Nuxt on front,
So GOAL :
Update an array of entity (AideSection) where one prop is OneToMany for another entity (AideSubSection::AideSection)
Here exemple of the structure of my item :
[
{
id: 0,
isActive: true,
libelle: "",
ordered: 0,
aideSubSection: [
{
id: 0,
isActive: true,
isForDashboard: true,
ordered: 0,
orderDashboard: 0,
aideSection: 0,
libelle: "",
content: ""
}
]
}
]
If I modify only data return by api and save , no problem, BUT when I try to save with new item, here is (partial) content of my post request:
enter image description here
So my ids are null, and here my controller and another file
#[Route("/backoffice/aide/save", name: "save_aide", methods: ["POST"])]
public function save(Request $request, AideSectionManager $manager) :JsonResponse
{
$post = $request->request->all();
/** #var AideSection $data */
foreach ($post as &$data) {
if (!empty($data['id'])) {
$section = $manager->find($data['id']);
} else {
$section = new AideSection();
}
$form = $this->createForm(AideSectionFormType::class, $section);
$form->submit($data);
if (!$form->isSubmitted() || !$form->isValid()) {
throw new Exception('Error');
}
$this->em->persist($section);
}
$this->em->flush();
return self::response('ok');
}
Here my FormType
For AideSection
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('libelle', TextType::class)
->add('isActive', CheckboxType::class)
->add('ordered', IntegerType::class)
->add('aideSubSection', CollectionType::class, [
'entry_type' => AideSubSectionFormType::class,
'allow_delete' => true,
'allow_add' => true
]);
}
For AideSubSection
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('libelle', TextType::class)
->add('content', TextType::class)
->add('isActive', CheckboxType::class)
->add('isForDashboard', CheckboxType::class)
->add('ordered', IntegerType::class)
->add('orderDashboard', IntegerType::class);
}
My Entity (with relation)
class AideSection
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
#[Groups('default')]
private $id;
#[ORM\Column]
#[Groups('default')]
private bool $isActive;
#[ORM\Column]
#[Groups('default')]
private string $libelle;
#[ORM\Column]
#[Groups('default')]
private int $ordered;
#[ORM\OneToMany(mappedBy: "aideSection", targetEntity: AideSubSection::class, cascade:
["persist"], fetch: "EAGER")]
#[Groups('default')]
private Collection $aideSubSection;
#[Pure] public function __construct()
{
$this->aideSubSection = new ArrayCollection();
}
class AideSubSection
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
#[Groups('default')]
private $id;
#[ORM\Column]
#[Groups('default')]
private string $libelle;
#[ORM\Column(type: Types::TEXT)]
#[Groups('default')]
private string $content;
#[ORM\Column]
#[Groups('default')]
private bool $isForDashboard;
#[ORM\Column]
#[Groups('default')]
private int $orderDashboard;
#[ORM\Column]
#[Groups('default')]
private int $ordered;
#[ORM\Column]
#[Groups('default')]
private bool $isActive;
#[ORM\ManyToOne(targetEntity: AideSection::class, inversedBy: "aideSubSection"),
ORM\JoinColumn(nullable: false)]
#[Groups('default')]
private AideSection $aideSection;
Same problem on my AideSection, I don't understand why it doesn't detect or update ids from my AideSetion or AideSubSection :/
Get the data from Form right after you checked if submitted and valid.
Then check if collection of aideSubSection isn't empty.
If it's not, loop through all, check if "new" (id is null) and persist.
if (!$form->isSubmitted() || !$form->isValid()) {
throw new Exception('Error');
}
$section = $form->getData(); // gives you instance of AideSection
// dd($section); // check data
// loop through all
foreach($section->getAideSubSection() as $aideSubSection){
// if "new"
if( $aideSubSection->getId === null ){
$this->em->persist($aideSubSection);
}
// make sure they are "linked"
$aideSubSection->setAideSection($section);
}
// persist only if $section is also "new"
if( $section->getId() === null ){
$this->em->persist($section);
}
$this->em->flush();