Trying to conver my sql queries into dql, seems im doing something wrong.
I need basic joins, something like this.
SELECT a.id, a.title, u.name FROM articles JOIN users ON a.author_id = u.id
Tried
SELECT a.id, a.title, u.name FROM Article a JOIN User u WITH a.author_id = u.id
Getting error
[Semantical Error] line 0, col 34 near 'Article a JOIN': Error: Class 'Article' is not defined.
How should i define? Could you give me please a right solution?
Edit:
Article Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="articles")
*/
class Article
{
/**
* #var integer $id
*
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $title;
/**
* #ORM\Column(type="integer", name="author_id")
*/
protected $authorId;
/**
* #ORM\Column(type="datetime", name="creation_date")
*/
protected $creationDate;
/**
* #ORM\Column(type="string", name="short_content")
*/
protected $shortContent;
/**
* #ORM\Column(type="string")
*/
protected $content;
public function getId()
{
return $this->id;
}
public function getTitle()
{
return $this->title;
}
public function getAuthorId()
{
return $this->authorId;
}
public function getCreationDate()
{
return $this->creationDate;
}
public function getShortContent()
{
return $this->shortContent;
}
public function getContent()
{
return $this->content;
}
}
User Entity
<?php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="bigint")
*/
protected $phone;
/**
* #ORM\Column(type="string")
*/
protected $gender;
/**
* #ORM\Column(type="string")
*/
protected $about;
public function getPhone()
{
return $this->phone;
}
public function getGender()
{
return $this->gender;
}
public function getAbout()
{
return $this->about;
}
}
Refer to the entities in your DQL by their namespaces, i.e. AppBundle:Article and AppBundle:User, that should make the error go away.
Use association mapping (old docs) instead of authorId in your entity, this way Doctrine will take care of loading the author:
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="author_id", referencedColumnName="id")
**/
private $author;
public function getAuthor() {
return $this->author;
}
public function setAuthor($author) {
$this->author = $author;
}
Your query would be reduced to:
SELECT a FROM AppBundle:Article a ORDER BY a.creationDate DESC
Once you have loaded an article, you can conveniently access the author:
...
$author = $article->getAuthor();
Related
I have 3 entities, User, Parking and Voiture.
User had a ManyToMany relation with parking while Parking has a OneToMany reamtion with voiture.
what I'm trying to do:
Get the cars (voitures) that belong to all parkings the currect user is related to
how I'm trying to do it:
Using querybuilder, but I still don't know how to make it work
here are my entities
Entity User:
<?php
/**
* #ORM\Entity
* #UniqueEntity(fields="username", message="Username already taken")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
public function getId()
{
return $this->id;
}
/**
* #ORM\Column(type="string", length=191, unique=true)
* #Assert\NotBlank()
*/
private $username;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Parking", mappedBy="agents")
*/
private $parkings;
public function __construct()
{
$this->parkings = new ArrayCollection();
}
/**
* #return Collection|Parking[]
*/
public function getParkings(): Collection
{
return $this->parkings;
}
public function addParking(Parking $parking): self
{
if (!$this->parkings->contains($parking)) {
$this->parkings[] = $parking;
$parking->addAgent($this);
return $this;
}
return $this;
}
public function removeParking(Parking $parking): self
{
if ($this->parkings->contains($parking)) {
$this->parkings->removeElement($parking);
$parking->removeAgent($this);
}
return $this;
}
}
Entity Parking:
<?php
/**
* #ORM\Entity(repositoryClass="App\Repository\ParkingRepository")
*/
class Parking
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=55)
*/
private $libelle;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\user", inversedBy="parkings")
*/
private $agents;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Voiture", mappedBy="parking", orphanRemoval=true)
*/
private $voitures;
public function __construct()
{
$this->agents = new ArrayCollection();
$this->voitures = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* #return Collection|user[]
*/
public function getAgents(): Collection
{
return $this->agents;
}
public function addAgent(user $agent): self
{
if (!$this->agents->contains($agent)) {
$this->agents[] = $agent;
}
return $this;
}
public function removeAgent(user $agent): self
{
if ($this->agents->contains($agent)) {
$this->agents->removeElement($agent);
}
return $this;
}
/**
* #return Collection|Voiture[]
*/
public function getVoitures(): Collection
{
return $this->voitures;
}
public function addVoiture(Voiture $voiture): self
{
if (!$this->voitures->contains($voiture)) {
$this->voitures[] = $voiture;
$voiture->setParking($this);
}
return $this;
}
public function removeVoiture(Voiture $voiture): self
{
if ($this->voitures->contains($voiture)) {
$this->voitures->removeElement($voiture);
// set the owning side to null (unless already changed)
if ($voiture->getParking() === $this) {
$voiture->setParking(null);
}
}
return $this;
}
}
And Entity Voiture
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\VoitureRepository")
*/
class Voiture
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=200)
*/
private $matricule;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Parking", inversedBy="voitures")
* #ORM\JoinColumn(nullable=false)
*/
private $parking;
/**
* #ORM\Column(type="boolean")
*/
private $parked;
public function getId(): ?int
{
return $this->id;
}
public function getMatricule(): ?string
{
return $this->matricule;
}
public function setMatricule(string $matricule): self
{
$this->matricule = $matricule;
return $this;
}
public function getParking(): ?Parking
{
return $this->parking;
}
public function setParking(?Parking $parking): self
{
$this->parking = $parking;
return $this;
}
}
I propose to add an intermediate entity UserParking between User and Parking entities.
So we have a OneToMany relationship between User and UserParking and a OneToMany relationship between Parking and UserParking instead of ManyToMany relationship between User and Parking.
The entities will be similar to code below:
Entity User:
<?php
/**
* #ORM\Entity
* #UniqueEntity(fields="username", message="Username already taken")
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
public function getId()
{
return $this->id;
}
/**
* #ORM\Column(type="string", length=191, unique=true)
* #Assert\NotBlank()
*/
private $username;
/**
* #ORM\OneToMany(targetEntity="App\Entity\UserParking", mappedBy="agent")
* #ORM\JoinColumn(nullable=true)
*/
private $user_parking;
// getter and setter
}
Entity Parking:
<?php
/**
* #ORM\Entity(repositoryClass="App\Repository\ParkingRepository")
*/
class Parking
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=55)
*/
private $libelle;
/**
* #ORM\OneToMany(targetEntity="App\Entity\UserParking", mappedBy="parking")
* #ORM\JoinColumn(nullable=true)
*/
private $user_parking;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Voiture", mappedBy="parking", orphanRemoval=true)
*/
private $voitures;
// getters and setters
}
Entity UserParking
/**
* UserParking
*
* #ORM\Table(name="user_parking")
* #ORM\Entity(repositoryClass="App\Repository\UserParkingRepository")
*/
class UserParking
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="user_parking")
* #ORM\JoinColumn(nullable=false)
*/
private $agent;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Parking", inversedBy="user_parking")
* #ORM\JoinColumn(nullable=false)
*/
private $parking;
// getter and setter
}
And Entity Voiture
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\VoitureRepository")
*/
class Voiture
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=200)
*/
private $matricule;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Parking", inversedBy="voitures")
* #ORM\JoinColumn(nullable=false)
*/
private $parking;
/**
* #ORM\Column(type="boolean")
*/
private $parked;
}
So to get the cars (voitures) that belong to all parkings the current user is related to you need to:
1- Get the current user object.
2- Get the UserParking array from the user object .
3- Get the Parking objects from the UserParking array.
4- Get the cars from the Parking objects.
The code will be similar to this:
$em = $this->getDoctrine()->getManager();
/* Get user from the session */
$user = $this->getUser();
$userParkings = $user->getUserParking();
$parkings = [];
foreach ($userParkings as $item) {
$parking = $item->getParking();
$parkings[count($parkings)] = $parking;
}
// you can get voitures from parkings
Start from Voiture entity and inner join the Parking and User entities using their associations:
$queryBuilder = $this->getDoctrine()->getRepository('App:Voiture')->createQueryBuilder('v');
$queryBuilder->innerJoin('v.parking', 'p');
$queryBuilder->innerJoin('v.agents', 'a');
Finally, you can filter on the relation either through a condition:
$queryBuilder->where('a.id = :userId');
$queryBuilder->setParameter("userId", 1);
$cars = $queryBuilder->getQuery()->getResult();
or place the condition on the $queryBuilder->innerJoin('v.agents', 'a', 'WITH', 'a.id = :userId'); see doctrine inner join with condition
References
SQL join: where clause vs. on clause
My relation between 2 entities is a OneToOne relation.
1) User Entity:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var $userContact
*
* #ORM\OneToOne(targetEntity="UserContact" , inversedBy="User")
* #ORM\JoinColumn(name="id", referencedColumnName="user_id", nullable=false)
**/
private $userContact;
/**
* #ORM\Column(type="string", length=255)
*/
private $last_name;
public function getId()
{
return $this->id;
}
public function getLastName(): ?string
{
return $this->last_name;
}
public function setLastName(string $last_name): self
{
$this->last_name = $last_name;
return $this;
}
}
UserContact Entity:
class UserContact
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $user_id;
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="UserContact")
*/
private $user;
/**
* #ORM\Column(type="string", length=255)
*/
private $mobile_number;
public function getId()
{
return $this->id;
}
public function getUserId(): ?int
{
return $this->user_id;
}
public function setUserId(int $user_id): self
{
$this->user_id = $user_id;
return $this;
}
public function getMobileNumber(): ?string
{
return $this->mobile_number;
}
public function setMobileNumber(string $mobile_number): self
{
$this->mobile_number = $mobile_number;
return $this;
}
}
My User Repository looks like this:
class UserRepository extends ServiceEntityRepository
{
public function index() {
return $this->createQueryBuilder('u')
->innerJoin('u.userContact', 'uc')
->getQuery()
->execute();
}
}
And the controller looks like this:
public function index()
{
$users = $em->getRepository('App:User')->index();
}
It's throwing an error like this one:
Missing value for primary key id on App\Entity\UserContact
In your association, the owning side is User and the inverse side is UserContact. You must use mappedBy for the inverse side instead inversedBy. So your annotation for the $user attribute in User entity must be this:
/**
* #ORM\OneToOne(targetEntity="User", mappedBy="UserContact")
*/
private $user;
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork-associations.html
In controller I try to retrieve all order products:
$products = $this->getDoctrine()->getRepository('AppBundle:Ordr')->find(1)->getOrdrProducts();
var_dump($products);
... but $products contain no products.
I try to imitate this.
Entity\Ordr.php :
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Table(name="ordr")
* #ORM\Entity
*/
class Ordr
{
public function __construct()
{
$this->ordr_products = new ArrayCollection();
}
/**
* #ORM\Column(name="idOrdr", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idordr;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="OrdrProduct", mappedBy="ordr")
*/
protected $ordr_products;
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getOrdrProducts()
{
return $this->ordr_products;
}
public function getIdordr()
{
return $this->idordr;
}
public function addOrdrProducts(\AppBundle\Entity\OrdrProduct $ordrProducts)
{
$this->ordr_products[] = $ordrProducts;
return $this;
}
public function removeOrdrProducts(\AppBundle\Entity\OrdrProduct $ordrProducts)
{
$this->ordr_products->removeElement($ordrProducts);
}
}
Entity\OrdrProduct.php :
/**
* #ORM\Table(name="ordr_products", indexes={#ORM\Index(name="idOrdr_idx", columns={"idOrdr"})})
* #ORM\Entity
*/
class OrdrProduct
{
/**
* #ORM\Column(name="idOrdrProduct", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $idordrproduct;
/**
* #ORM\Column(type="string")
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Ordr", inversedBy="ordr_products")
* #ORM\JoinColumn(name="idOrdr", referencedColumnName="idOrdr")
*/
private $ordr;
public function getIdordrproduct()
{
return $this->idordrproduct;
}
public function setOrdr(\AppBundle\Entity\Ordr $ordr = null)
{
$this->ordr = $ordr;
return $this;
}
public function getOrdr()
{
return $this->ordr;
}
}
My post is mostly code, I apologize for that. I dont know what to add more about the issue.
I can add something more about something else.
Hope this will help you:
Try this to get one order by id (with all order products related to it)
#AppBundle\Repository\OrderRepository.php
public function findOrderById($id)
{
$qb = $this->createQueryBuilder('o')
->join('o.ordr_products', 'r')
->addSelect('r')
->where('o.id = :id')
->setParameter(':id', $id)
;
return $qb->getQuery()
->getOneOrNullResult();
;
}
I have many to many relationship between user and groups, but when I want to access all groups for user I get empty collection.
namespace LoginBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="User")
*/
class User
{
/**
* #ORM\Column(type="integer", name="id")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $_iId;
/**
* #ORM\Column(type="string", name="login", length=45)
*/
private $_sLogin;
/**
* #ORM\ManyToMany(targetEntity="GroupBundle\Entity\Group", inversedBy="_aUser")
* #ORM\JoinTable(name="Group_x_User",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
private $_aGroup;
public function __construct() {
$this->_aGroup = new ArrayCollection();
}
/**
* Get iId
*
* #return integer
*/
public function getId()
{
return $this->_iId;
}
/**
* Set sLogin
*
* #param string $sLogin
*
* #return User
*/
public function setLogin($sLogin)
{
$this->_sLogin = $sLogin;
return $this;
}
/**
* Get sLogin
*
* #return string
*/
public function getLogin()
{
return $this->_sLogin;
}
public function getGroups()
{
return $this->_aGroup;
}
User and Group use Group_x_User table to store their relationships.
namespace GroupBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="Group")
*/
class Group
{
/**
* #ORM\Column(type="integer", name="id")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $_iId;
/**
* #ORM\Column(type="string", name="name", length=45)
*/
private $_sName;
/**
* #ORM\ManyToMany(targetEntity="LoginBundle\Entity\User", mappedBy="_aGroup")
*/
private $_aUser;
public function __construct() {
$this->_aUser = new ArrayCollection();
}
/**
* Get iId
*
* #return integer
*/
public function getId()
{
return $this->_iId;
}
/**
* Set sName
*
* #param string $sName
*
* #return Group
*/
public function setName($sName)
{
$this->_sName = $sName;
return $this;
}
/**
* Get sName
*
* #return string
*/
public function getName()
{
return $this->_sName;
}
public function getUsers()
{
return $this->_aUser;
}
}
For restoring data from database I use code:
$oUser = $this->getDoctrine()
->getRepository('LoginBundle:User')
->find(2);
$aGroup = $oUser->getGroups();
Unfortunatelly $aGroup collection contains array of 0 elements while in database are records which are matching. What am I missing in my mapping?
There is something missing from your User class. You only declare _aGroup with ArrayCollection. This is not enough. You have to store the data into ArrayCollection.
Add this into User class.
public class addGroups(\GroupBundle\Entity\Group $group)
{
$group->addUsers($this);
$this->_aGroup->add($group);
}
This is for Group class.
public class addUsers(\LoginBundle\Entity\User $user)
{
if (!$this->_aUser->contains($user)) {
$this->_aUser->add($user);
}
}
For more information, you can visit this link.
#ORM\JoinTable() annotation syntax on User::$_aGroup definition is intended to be used for self-referencing relations Doctrine documentation.
Try using simplified syntax :
#JoinTable(name="Group_x_User")
If you use common conventions ('id' as column name for identifiers, and so on) Doctrine and Symfony will do the rest for you.
I have this three tables in my model:
And I need to create the relationship between them in order to get valid entities but I need some help here. This is what I have right now:
Proyectos.php
<?php
namespace PI\ProyectoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="proyectos")
*/
class Proyectos {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=45, unique=true, nullable=false)
*/
protected $nombre;
/**
* #ORM\Column(type="boolean", nullable=true)
*/
protected $estado;
/**
* #ORM\Column(type="string", length=45, nullable=false)
*/
protected $pais;
/**
* #ORM\ManyToOne(targetEntity="PI\ClienteBundle\Entity\Clientes", cascade={"all"})
* #ORM\JoinColumn(name="cliente", referencedColumnName="id")
*/
protected $clientes;
public function getId() {
return $this->id;
}
public function setNombre($nombre) {
$this->nombre = $nombre;
}
public function getNombre() {
return $this->nombre;
}
public function setEstado($estado) {
$this->estado = $estado;
}
public function getEstado() {
return $this->estado;
}
public function setPais($pais) {
$this->pais = $pais;
}
public function getPais() {
return $this->pais;
}
public function setClientes(\PI\ClienteBundle\Entity\Clientes $clientes) {
$this->clientes = $clientes;
}
public function getClientes() {
return $this->clientes;
}
}
And Centros.php
<?php
namespace PI\CentroBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="centros")
*/
class Centros {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="text", unique=true, nullable=false)
*/
protected $descripcion;
/**
* #ORM\ManyToMany(targetEntity="PI\UnidadBundle\Entity\Unidades", inversedBy="centros", cascade={"persist"})
* #ORM\JoinTable(name="unidades_has_centros",
* joinColumns={#ORM\JoinColumn(name="centros_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="unidades_id", referencedColumnName="id")}
* )
*/
protected $unidades;
public function __construct() {
$this->unidades = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getId() {
return $this->id;
}
public function setDescripcion($descripcion) {
$this->descripcion = $descripcion;
}
public function getDescripcion() {
return $this->descripcion;
}
public function setUnidades(\PI\UnidadBundle\Entity\Unidades $unidades) {
$this->unidades[] = $unidades;
}
public function getUnidades() {
return $this->unidades;
}
}
How I add the n:m relationship in both sides to get valid entities and to make CRUD operations more easy than create a new Entity ProyectosHasCentros.php and put fields inside it?
If you don't add proyectos_cliente to the second table you can use the ManyToMany relationships in your entities. If you want extra fields, then you have to create an extra entity which contains the relationships with Proyectos and Centros. Beside the relationships you add extra properties, like proyectos_cliente.
Try to use one PK and use UNIQUE for the cliente field