I have a many to many relation with Employee and MembreFamille. And i want to get all MembreFamilles that have an Employee.
This is my query :
class MembreFamilleRepository extends EntityRepository
{
public function getMembres($emp)
{
$qb = $this->createQueryBuilder('a');
$qb
->leftJoin('a.employees', 'employees');
$qb
->where('employees.id = :id')
->setParameter('id', $emp);
return $qb
->getQuery()
->getResult()
;
}
}
When I test this function in the controller , the function return 0 result.
The mapping in Employee Entity:
/**
* #ORM\ManyToMany(targetEntity="PFE\EmployeesBundle\Entity\MembreFamille", cascade={"persist"})
*/
private $membreFamilles;
The Mapping in MembreFamille Entity :
/**
* #ORM\ManyToMany(targetEntity="PFE\UserBundle\Entity\Employee", cascade={"persist"})
*/
private $employees;
The use in the Controller ($employee is an instance of Employee Entity ) :
$list = $em->getRepository('PFEEmployeesBundle:MembreFamille')->getMembres($employee->getId());
You need to add a JoinTable for your ManyToMany association and set the owning and inverse sides:
/**
* #ORM\ManyToMany(targetEntity="PFE\EmployeesBundle\Entity\MembreFamille",
* cascade={"persist"}, mapped="employees")
*/
private $membreFamilles;
.................................
/**
* #ORM\ManyToMany(targetEntity="PFE\UserBundle\Entity\Employee", cascade={"persist"}, inversedBy="membreFamilles")
* #ORM\JoinTable(name="membre_familles_employees")
*/
private $employees;
You can use a construction called "MEMBER OF".
class MembreFamilleRepository extends EntityRepository
{
public function getMembres($emp)
{
return $this->createQueryBuilder('a');
->where(':employee MEMBER OF a.employees')
->setParameter('employee', $emp)
->getQuery()
->getResult()
;
}
}
You can use a construction called "MEMBER OF"
Related
I'm trying to execute a query to obtain all the Repos from an specific Organization, but it returns an empty result... (I have data in the DB!)
Repos and Organization are a Many to Many relation.
Here's the Repos Entity:
/**
* Repos
*
* #ORM\Table(name="repos")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ReposRepository")
*/
class Repos
{
...
/**
*
* #ManyToMany(targetEntity="Organization", inversedBy="repos")
*
*/
protected $orgs;
...
Here's the Organization Entity:
/**
* Organization
*
* #ORM\Table(name="organization")
* #ORM\Entity(repositoryClass="AppBundle\Repository
* \organizationRepository")
*/
class Organization
{
...
/**
*
* #ORM\ManyToMany(targetEntity="Repos", mappedBy="orgs")
*
*/
protected $repos;
...
}
Here's the Repository with the QueryBuilder:
/**
* ReposRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class ReposRepository extends \Doctrine\ORM\EntityRepository
{
public function findReposByName($name){
$qb = $this->createQueryBuilder('r');
// Build query
$qb->select('r')
->andWhere(
':searchName MEMBER OF r.orgs'
);
$qb->setParameter('searchName',$name);
return $qb->getQuery()->getResult();
}
}
The $name is the name of an Organization and I want to obtain all the Repos with the the same organization name.
If you want to filter with the name attribute of your Organization, you have to do a join query.
With the query builder
public function findReposByName($name){
$qb = $this->createQueryBuilder('r');
$qb->select('r')
->join('r.orgs', 'o')
->where('o.name = :searchName')
->setParameter('searchName', $name);
return $qb->getQuery()->getResult();
}
In DQL
public function findReposByName($name){
$dql =<<<EOF
SELECT r
FROM AppBundle:Repos r
INNER JOIN r.orgs o
WHERE o.name = :searchName
EOF;
return $this->_em
->createQuery($dql)
->setParameter('searchName',$name)
->getResult();
}
I have 2 entities connected with many to many relation into a 3th table, and I want to get every color for an id of product:
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Color", inversedBy="products")
* #ORM\JoinTable(name="products_colors",
* joinColumns={#ORM\JoinColumn(name="product_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="color_id", referencedColumnName="id")}
* )
*/
private $colors;
And in my second entity:
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Product", mappedBy="colors")
*/
private $products;
This is my query: (I was trying to make some joins but cant make it work)
class ProductRepository extends \Doctrine\ORM\EntityRepository
{
public function getColors($id)
{
$query = $this->createQueryBuilder('p')
->join('AppBundle\Entity\Color', 'c')
->where('c.product_id = :id')
->setParameter('id', $id)
->getQuery()
->getResult();
return $query;
}
}
I got this error:
[Semantical Error] line 0, col 85 near 'product_id =': Error: Class
AppBundle\Entity\Color has no field or association named product_id
which I understand, but can't think of a way to make this work.
Symfony expects you to reference the entity (not id) of an object when mapped by ManyToMany relationship. Try:
class ProductRepository extends \Doctrine\ORM\EntityRepository
{
public function getColors(Product $product)
{
$query = $this->createQueryBuilder('p')
->join('AppBundle\Entity\Color', 'c')
->where('c.product = :product')
->setParameter('product', $product)
->getQuery()
->getResult();
return $query;
}
}
Of course you'll have to modify your call to this function accordingly.
You can also skip the query creation altogether with the getter function in your entity; symfony automagically will do the query for you.
// class Product
private $colors; // as you have it set up already
/**
* #return ArrayCollection|Color[]
*/
public function getColors()
{
return $this->colors;
}
I have the following tables, where I have no problem in inserting, updating etc. But, how can I fetch the result rows for this kind of mapping?
Organizations
-->id
-->name
users
-->id
-->first_name
doctors
-->id
-->user_id
org_doctors
-->id
-->org_id
-->doctor_id
This is my OrgDoctor Entity:
<?php
namespace Doctor\Entity;
use Doctrine\ORM\Mapping as ORM;
use Library\Entity\BaseEntity;
use User\Entity\User;
use Doctor\Entity\Doctor;
use Organization\Entity\Organization;
/**
* #ORM\Entity
* #ORM\Table(name="org_doctors")
*/
class OrgDoctor extends BaseEntity{
/**
* #ORM\ManyToOne(targetEntity="Doctor\Entity\Doctor", inversedBy="orgDoctor")
* #ORM\JoinColumn(name="doctor_id",referencedColumnName="id",nullable=false)
*/
protected $doctor;
/**
* #ORM\ManyToOne(targetEntity="Organization\Entity\Organization", inversedBy="orgDoctor")
* #ORM\JoinColumn(name="org_id", referencedColumnName="id", nullable=false)
*/
protected $organization;
public function setDoctor(Doctor $doctor = null)
{
$this->doctor = $doctor;
return $this;
}
public function getDoctor()
{
return $this->doctor;
}
public function setOrganization(Organization $organization = null)
{
$this->organization = $organization;
return $this;
}
public function getOrganization()
{
return $this->organization;
}
}
And this is my Doctor Entity:
<?php
namespace Doctor\Entity;
use Library\Entity\BaseEntity;
use Users\Entity\User;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="doctors")
*/
class Doctor extends BaseEntity {
/**
* #ORM\OneToOne(targetEntity="Users\Entity\User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
* #var Users\Entity\User
*/
private $user;
/**
* #ORM\Column(name="summary", type="string")
* #var string
*/
private $summary;
function getUser() {
return $this->user;
}
function setUser(User $user) {
$this->user = $user;
}
function getSummary() {
return $this->summary;
}
function setSummary($summary) {
$this->summary = $summary;
}
}
This is how I'm fetching the result for a single doctor:
$doctor = $this->entityManager->find('Doctor\Entity\Doctor', (int) $doctorId);
How can I fetch rows from the OrgDoctor entity?
this is how i tried using queryBuilder:
$qb = $this->entityManager->createQueryBuilder();
$qb->select('od', 'd', 'o')
->from('Doctor\Entity\OrgDoctor', 'od')
->join('od.organization', 'o')
->join('od.doctor', 'd')
->where('od.organization = :organization')
->setParameter('organization', $orgId);
$query = $qb->getQuery();
$results = $query->getResult();
var_dump($results);
Notice: Undefined index: orgDoctor in C:\xampp\htdocs\corporate-wellness\vendor\doctrine\orm\lib\Doctrine\ORM\Internal\Hydration\ObjectHydrator.php on line 125
In Organization Entity:
/**
* #ORM\OneToMany(targetEntity="Doctor\Entity\OrgDoctor", mappedBy="organization")
*/
protected $orgDoctor;
Given your entity mapping, Doctrine should provide you with an out of the box repository for your OrgDoctor entity. That repository implements a few methods for you to retrieve entities of that type. One of them is findBy, which return arrays of OrgDoctor entities:
$this->getEntityManager()->getRepository(OrgDoctor::class)->findBy(['doctor' => $doctorId]));
$this->getEntityManager()->getRepository(OrgDoctor::class)->findBy(['organization' => $organizationId]));
$this->getEntityManager()->getRepository(OrgDoctor::class)->findBy(['doctor' => $doctorId, 'organization' => $organizationId]));
The last example, would be quite similar to findOneBy, which would return an OrgDoctor entity instead of an array:
$this->getEntityManager()->getRepository(OrgDoctor::class)->findOneBy(['doctor' => $doctorId, 'organization' => $organizationId]));
If you're planning to loop through the results and access their properties or other relationships, you might want to change the default repository strategy and define a custom repository for your OrgDoctor entity. What this will allow you to do, is to write your custom queries for retrieving your entities by means of a query builder class and DQL.
In order to avoid N+1 problems, you want to fetch join before a loop to fetch all the necessary associations in one go, so you won't be running N queries within your loop:
$qb->select('od', 'd', 'o')
->from(OrgDoctor::class, 'od')
->join('od.organization', 'o')
->join('od.doctor', 'd')
->where('od.doctor = :doctor')
->setParameter('doctor', $doctorId)
;
Iam learning Doctrine.
I have two entities Article and Category in many to many relationship and iam trying to get all categories where isnt specific article.
ArticleEntity:
class Article extends BaseEntity
{
use Identifier;
/**
* #ORM\Column(type="string", nullable = false, unique=TRUE)
* #var string
*/
private $title;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="articles")
* #ORM\JoinTable(name="article_categories")
*/
private $categories;
public function getCategories()
{
return $this->categories;
}
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
And CategoryEntity:
class Category extends BaseEntity
{
use Identifier;
/**
* #ORM\Column(type="string", nullable = false, unique=true)
* #var string
*/
private $title;
/**
* #ORM\Column(type="string",nullable=false,unique=true)
* #var sting
*/
private $slug;
/**
* #ORM\ManyToMany(targetEntity="Article", mappedBy="categories")
*/
private $articles;
public function __construct()
{
$this->articles = new \Doctrine\Common\Collections\ArrayCollection();
}
And i am trying to get all categories without specific article. In pure MySQL id would be something like this:
SELECT * FROM category LEFT JOIN article_categories ON category.id = article_categories.category_id WHERE article_categories.article_id <> 1(for example) AND article_id IS NOT NULL
And the only solution i could create in my CategoryRepository is this one.
public function findWithoutArticle($article_id)
{
$articleCat = $this->em->find(Article::getClassName(), $article_id);
$qb = $this->em->createQueryBuilder();
$qb->select('c')
->from(Category::getClassName(), 'c')
->where('c.id NOT IN (:article_id)')
->setParameter('article_id', $articleCat->getCategories()->toArray());
return $qb->getQuery()->getResult();
}
And this doesnt look right. Is there any better "Doctrine way" practice?
How about this one?
$qb = $this->em->createQueryBuilder();
$qb->select('c');
$qb->from('Category', 'c');
$qb->leftJoin('c.articles', 'a');
$qb->where($qb->expr()->neq('a.article_id', '?1'));
$qb->setParameter(1, $article_id);
$categories = $qb->getQuery()->getResult();
How about this:
public function findWithoutArticle($article_id)
{
$qb = $this->em->createQueryBuilder()
->select('c')
->from('Category', 'c')
->leftJoin('c.article', 'a')
->where('a.article_id <> :articleId')
->setParameter('articleId', $article_id);
return $qb->getQuery()->getResult();
}
I have two entity classes, Product and OrderEntry, defined like this (some annotations left out for compactness):
class Product {
/**
* #Id
*/
protected $id;
/**
* #Column()
* #Id
*/
protected $prodNumber;
/**
* #Column()
* #Id
*/
protected $group;
// more cols here
}
class OrderEntry {
// more cols here
/**
* #ManyToOne(targetEntity="Product")
* #JoinColumns({
* #JoinColumn(name="prodNumber", referencedColumnName="prodNumber"),
* #JoinColumn(name="group", referencedColumnName="group")
* })
*/
protected $Product;
}
Now I want to find an OrderEntry by its associated Product with the query builder. The most logical thing for me would be this:
class OrderEntryRepository extends EntityRepository {
public function findByProduct($product) {
$qb = $this->getQueryBuilder('o');
$qb->where($qb->expr()->eq('o.Product', '?1')
->setParameter(1, $product)
->setMaxResults(1);
return $qb->getQuery()->execute();
}
}
However, this throws an exception that says
A single-valued association path expression to an entity with a
composite primary key is not supported. Explicitly name the components
of the composite primary key in the query.
How do I name the components explicitly? I know I could do it with a JOIN, but I have no use for the Product in this case and it would just make the query more expensive.
You can't avoid joining the products table with the current mapping:
public function findByProduct($product) {
$qb = $this->getQueryBuilder('o');
$qb
->join('o.Product', 'p')
->where('p.prodNumber = ?1')
->setParameter(1, $product->getProdNumber())
->andWhere('p.group = ?2')
->setParameter(2, $product->getGroup())
;
return $qb->getQuery()->getOneOrNullResult();
}
You can add separate properties to OrderEntry, which would use the same columns as the JoinColumns, e.g.:
/**
* #Column(name="prodNumber")
*/
protected $prodNumber;
And then you can use them in conditions:
...
->where('o.prodNumber = ?1')
->setParameter(1, $product->getProdNumber()
...