Doctrine2 Associations mapping and doctrine annotations - php

I've broken my head trying to set annotations for my 2 entities in order to use join tables.
I have 2 tables: user and cart.
Cart contains user ids with products which users selected.
1 user can have many products, so it's a ManyToOne relationship.
When I tried to set up the associations I tried a lot of different things and none of them worked. Now I'm having this:
// ---------------- USER CLASS ------------------- //
/**
* #ORM\Entity
* #ORM\Table(name="user", indexes={#ORM\Index(name="firstname_idx", columns={"firstname"}), #ORM\Index(name="lastname_idx", columns={"lastname"}), #ORM\Index(name="email_idx",columns={"email"})})
*/
class User
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="string", length=100)
*/
public $firstname;
/**
* #ORM\Column(type="string", length=100)
*/
public $lastname;
/**
* #ORM\Column(type="string", length=100, nullable=true)
*/
public $email;
/**
* #ORM\OneToMany(targetEntity="Cart", mappedBy="users")
**/
public $cart;
public function __construct() {
$this->cart = new ArrayCollection();
}
//...
And the Cart class:
/**
* #ORM\Entity
* #ORM\Table(name="cart")
*/
class Cart {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
public $user_id;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="cart")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
**/
public $users;
public function __construct() {
$this->users = new ArrayCollection();
}
When I execute a query with join of these tables I receive the message:
"[Semantical Error] line 0, col 84 near 'u': Error: Class Cart has no association named User"
My query looks like this:
$q = $db->em->createQueryBuilder()
->select('c.*, u.*')
->from("Application\Entity\Cart","c")
->join("c.Application\Entity\User","u")
->getQuery();
What am I doing wrong? How to set the annotaions?
I'll appreciate any help.

Well, I figured it out by myself and again I'm answering my own question.
I spent several days on trying to fix the annotations. But the real problem was in the query.
I was trying to join entities as I was always doing it in Doctrine1. But in Doctrine2 when you join tables you have to join with the parameter you defined in the entity as the join parameter. So in my case it would be:
$q = $db->em->createQueryBuilder()
->select('c, u')
->from("Application\Entity\Cart","c")
->join("c.users","u")
->getQuery();
That was tricky for one that is used to work with doctrine1...

Related

easyadmin 3 - Sorting by linked entity’s property instead of id

I have one entity Hike which have relation with another named Department
<?php
class Hike
{
private $id;
private $name;
private $description;
/**
* #ORM\ManyToOne(targetEntity=Department::class, inversedBy="hikes")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotBlank(message="libdepartmentRequired")
*/
private $department;
// ...
}
<?php
class Department
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=3)
*/
private $department_code;
/**
* #ORM\Column(type="string", length=255)
*/
private $department_nom;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Hike", mappedBy="department")
*/
private $hikes;
// ...
}
In easyAdmin3 rendering is fine like
But when I sorting by department I see that easyAdmin3 sort by department's id, and I would like sorting by department_nom
I saw many solutions but they all using easyAdmin2 and easy_admin.yaml which no longer exists now.
There is a way to achieve that ?
Use configureCrud. Something like this should do the trick.
public function configureCrud(Crud $crud): Crud
{
return $crud
->setDefaultSort(['departement' => 'DESC'])
;
}
You can also use the filter to get the resultat wanted.

Doctrine won't join two columns- Using Symfony2 and Doctrine

I have two tables:
Posts
id | title | content | user
Users
id | name
and I want to have user name in Posts collection. What am I doing wrong here? Do I have to write custom query to do this?
Right now I'm getting user's id in posts collection.
class Posts
{
...
/**
* #ORM\Column(name="user", type="text", length=250)
* #ORM\ManyToOne(targetEntity="Users", inversedBy="posts")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
...
User class:
class Users
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="text", length=250)
*/
public $name;
/**
* #ORM\OneToMany(targetEntity="Posts", mappedBy="user")
*/
protected $posts;
...
you have an error in your $user relation annotation, you can't make a column be a regular #ORM\Column AND a #ORM\JoinColumn, try:
/**
* #ORM\ManyToOne(targetEntity="Users", inversedBy="posts")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
protected $user;
this will give you the entity(referencedColumnName must be primary key), then you can do $user->getName();

Delete link between two table with a query builder

I have made a queryBuilder inside an entity repository to delete a link between two table.
I have this two entities
Domain :
/**
* #var int
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", length=64)
* #Assert\NotBlank
* #Assert\Length(max="64")
* #AppAssert\DomainName
*/
private $name;
// Some other fields
/**
* #var SshKey[]|ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\SshKey", inversedBy="domains")
* #ORM\JoinTable(name="domain_sshkey",
* joinColumns={#ORM\JoinColumn(referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="key_id", referencedColumnName="id")}
* )
*/
private $sshKeys;
And SshKeys :
/**
* #var int
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $createdAt;
// Other fields
/**
* #var Domain[]|ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Domain", mappedBy="sshKeys")
*/
private $domains;
I am trying to delete links between this two tables when SshKeys id is in sshKeys field inside domain table.
So I made this query builder in my DomainRepository
public function deleteSshkeyDomainLink($invalidSshkey)
{
$qb = $this->createQueryBuilder('d');
$qb->delete()
->where($qb->expr()->in('ssh.id', ':ssh_keys_id'))
->setParameter('ssh_keys_id', $invalidSshkey)
->join('d.sshKeys', 'ssh')
;
return $qb->getQuery()->execute();
}
But this QB return this error
[Doctrine\ORM\Query\QueryException]
[Semantical Error] line 0, col 39 near 'ssh.id IN(:s': Error: 'ssh' is not defined.
[Doctrine\ORM\Query\QueryException]
DELETE AppBundle\Entity\Domain d WHERE ssh.id IN(:ssh_keys_id)
I don't understand why this is returning ssh is not defined because I have made a join with this alias.
This query builder should work ? I really don't know how too fix this.
Thanks for your help.
why do you want to delete Domain when you just need to delete sshKey from Domain (link between them)?
In Domain entity you can define method removeSshKey like this for example
public function removeSshKey(SshKey $key)
{
$this->sshKeys->removeElement($key);
return $this;
}
Then in controller where you want to delete the link between entities you should call it something like this
$domain = $this->getDoctrine()->getRepository('Domain')->find($domainId);
foreach ($domain->getSshKeys() as $sshKey)
{
if ($sshKey->getId() == $invalidSshKeyId)
{
$domain->removeSshKey($sshKey);
}
}
$em = $this->getDoctrine()->getManager();
$em->flush();
this should delete the link

OneToMany ManyToOne DoctrineORM Error

I'm newbie with PHP. I started work with symfony but i have this problem
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param \Doctrine\Common\Collections\Collection $carList
* #ORM\OneToMany(targetEntity="AppBundle\CarBundle\Entity\Car", mappedBy="name", cascade={"persist"})
*/
private $carList;
//getters and setters
}
*
* #ORM\Entity(repositoryClass="AppBundle\CarBundle\Repository\Entity\CarRepository")
* #ORM\Table(name="car")
*/
class Car
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
*
*/
protected $id;
/**
* #ORM\Column(type="string", length=100)
* #ORM\ManyToOne(targetEntity="AppBundle\UserBundle\Entity\User" , inversedBy="carList")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $name;
//getters and setters
}
The stacktrace says:
Symfony\Component\Debug\Exception\ContextErrorException: Notice: Undefined index: name
at n/a
and when i run php bin/console doctrine:schema:validate
[Mapping] FAIL - The entity-class 'AppBundle\UserBundle\Entity\User'
mapping is invalid:
* The association AppBundle\UserBundle\Entity\User#carList refers to the owning side field AppBundle\CarBundle\Entity\Car#name which is not
defined as association, but as field.
*The association AppBundle\UserBundle\Entity\User#carList refers to the owning side field Appbundle\CarBundle\Entity\Car#name which does
not exist
I have no idea whats going on, can you help me?
You are mixing up association names with column names. When you create an association you don't need to manually add the columns for that association, doctrine will work that out for you.
This code (in the Car class) says that the $name field is a normal text column in the car table, which of course is wrong
* #ORM\Column(name="name",type="string", length=100)
What you're describing is that one user can own many cars, and many cars can belong to one user. I'd then call the associations owner and cars, but you are of course free to call them whatever you want. Note that you do not need to define the join columns.
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #param \Doctrine\Common\Collections\Collection $cars
* #ORM\OneToMany(targetEntity="AppBundle\CarBundle\Entity\Car", mappedBy="owner", cascade={"persist"})
*/
private $cars;
public function __construct()
{
$this->cars = new \Doctrine\Common\Collections\ArrayCollection();
}
//getters and setters
}
 
/**
*
* #ORM\Entity(repositoryClass="AppBundle\CarBundle\Repository\Entity\CarRepository")
* #ORM\Table(name="car")
*/
class Car
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\UserBundle\Entity\User" , inversedBy="cars")
*/
private $owner;
//getters and setters
}
Read more: Doctrine association mapping
Hope it makes sense :)

Relationship between two intermediate entities in Symfony2

I have five entities :
ProductA, ProductB, User, UserProductA and UserProductB. The two last ones are "intermediate" entites which contain the attributes of relationships between ProductA, ProductB and User.
I would like to make a ManyToOne relationship between UserProductA and UserProductB but it doesn't work. When I try to update the database, I get this error : Single id is not allowed on composite primary key in entity.
UserProductA (without the relationship) :
/**
* #ORM\Entity(repositoryClass="Gam\UserBundle\Entity\UserProductARepository")
*/
class UserProductA
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\FicheBundle\Entity\ProductA")
*/
private $producta;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\UserBundle\Entity\User")
*/
private $user;
/**
* #ORM\Column(type="string", length=1, nullable=true)
*/
private $attribute;
etc...
}
UserProductB (without the relationship) :
/**
* #ORM\Entity(repositoryClass="Gam\UserBundle\Entity\UserProductBRepository")
*/
class UserProductB
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\FicheBundle\Entity\ProductB")
*/
private $productb;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Gam\UserBundle\Entity\User")
*/
private $user;
/**
* #ORM\Column(type="string", length=1, nullable=true)
*/
private $attribute;
etc...
}
How can I make it work ?

Categories