How to make a join query on Symfony with Doctrine? - php

I'm kinda stuck on using the querybuilder to create a join query.
There is a table called "Person" and a table called "Vacancy". If a person is linked to the vacancy the person.id and vacancy.id is saved in a table called "Candidacy". So how do I get all the persons who are linke to vacancy.id 1?
So where do I have to initiate the AppBundle:Candidacy entity?
$entity = $em
->getRepository('AppBundle:Person')
->createQueryBuilder('p')
->join('p.id', 'c')
->where('c.vacancyId= 1')
->getQuery()
->getResult();
Thank you in advance.

Example in your repository :
public function getPersonVacancy($personId) {
$qb = $this->createQueryBuilder('p');
$qb->leftJoin('p.vacancy', 'v');
$qb->select('v.name', 'v.id');
$qb->where('p.id = :personId');
$qb->setParameter('personId', $personId);
return $qb ->getQuery()->getResult();
This is to give you an example it may not work with copy paste.
Also, all join methods are explained in doctrine documentation, feel free to read it http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html

Looks like you have many-to-many relation.
You should link your Person and Vacancy table through Candidacy to Person and then Vacancy to Candidacy.
small example: Entity User is attached to Engagement via UserEngagement table.
$qb = $this->_em->createQueryBuilder()
->select('u')
->from($this->_entityName, 'u')
->join('u.userEngagements', 'ue')
->join('ue.engagement', 'en')
...

Related

Transpose a raw SQL query with doctrine

I'm pretty new to Doctrine ORM and I'm trying to transform a raw SQL query with doctrine to get an array of Entities.
Basically I want to get one of more course entities where a user is indirectly registered. The course id is in a traineeship table. The traineeship id and the user id are in a registration table.
Here's my SQL query :
SELECT * FROM course c
LEFT JOIN traineeship t
ON c.id = t.courseId
LEFT JOIN registration r
ON t.id = r.traineeshipId
WHERE r.userId = 2681;
Here's what I try to do with doctrine :
return $this->createQueryBuilder('c')
->andWhere('t.course = c')
->leftJoin('c.traineeships', 't')
->andWhere('r.traineeship = t')
->leftJoin('t.registrations', 'r')
->andWhere('r.id = :user')
->setParameter('user', $user)
->getQuery()
->execute();
With my raw SQL query, I get two expected results with a given id. With the generated query by doctrine, I get only one result. So I guess my doctrine use is bad.
(Doctrine relations :
Course OneToMany Traineeship
Traineeship OneToMany Registration
Registration ManyToOne User)
From the raw SQL I would expect the following query:
return $this->createQueryBuilder('c')
->leftJoin('c.traineeships', 't')
->leftJoin('t.registrations', 'r')
->andWhere('r.user = :user')
->setParameter('user', $user)
->getQuery()
->getResult();
Please note that I'm using ->andWhere('r.user = :user') instead of ->andWhere('r.id = :user') as I assume that registration.id holds the id of the registration but not the id of the user. In my query I furthermore assume that registration has an attribute user which holds a reference to the user.
The query should return an array of course entities.

Symfony Doctrine findBy and then map

Basically I want to execute this mysql query with doctrine:
select distinct user_id from work_hour where project_id = ?;
But I don't know how I can do this with pretty Doctrine code. Is it possible to make it look like the following pseudo code or do I have to use the query builder?:
$project = new Project();
...
$entities = $em->getRepository('AppBundle:WorkHour')
->findByProject($project)->selectUser()->distinct();
Where $entities is an array of User objects
WorkHour and Project have a ManyToOne relation
WorkHour and User have a ManyToOne relation
You'll need to use a QueryBuilder for that, but that would still be quite a "pretty Doctrine code" and would still look quite like your pseudo-code.
Something like this should work:
$queryBuilder = $em->createQueryBuilder();
$query = queryBuilder
->select('u')
->distinct()
->from('AppBundle:User', 'u')
->join('AppBundle:WorkHour', 'wh')
->where('u.workHour = wh')
->andWhere('wh.project = :project')
->getQuery();
$query->setParameter(':project', $project);
$entities = $query->getResult();
public function findByProject($project)
{
$qb = $this->getEntityManager()->createQueryBuilder('User');
$qb
->select('User')
->from('Path\Bundle\Entity\User', 'User')
->join('Path\Bundle\Entity\WorkHour', 'wh',
'WITH', 'User.workHour = wh')
->where('wh.project = :project'))
->distinct()
->setParameter('project', $project)
;
$query = $qb->getQuery();
return $query->getResult();
}
If you have a complicated query you should do it in QueryBuilder, it'll be more efficient.
http://doctrine-orm.readthedocs.org/en/latest/reference/query-builder.html
If you have complicated queries you shouldn't do it directly into the controller, it shouldn't know this logic, you have to do it in the repository and call it from there

Doctrine2 get object without relations

An user has one role.
A role has zero or many users.
I would like to find roles without users.
I need to have this query without using IN or NOT IN
I tried with join:
$qb = $this->createQueryBuilder('role');
$qb
->leftJoin('role.users', 'users')
->where('users IS NULL')
without join
$qb = $this->createQueryBuilder('role');
$qb
->where('role.users IS NULL')
with id:
$qb = $this->createQueryBuilder('role');
$qb
->leftJoin('role.users', 'users')
->where('users.role != role')
Do you have other ideas? Do I have no other choices than to use IN / NOT IN queries?
Thanks in advance
You can find roles that don't have any users by using a count query
$qb = $this->createQueryBuilder('role');
$qb ->addSelect('COUNT(users.id) AS total_users')
->leftJoin('role.users', 'users')
->groupBy('role.id')
->having('total_users = 0')
->getQuery()->getResult();

Doctrine2 fetching rows that have manyToMany association by QueryBuilder

everyone.
I have 2 entities City and POI. Mapping looks like this:
class City {
/**
* #ORM\ManyToMany(targetEntity="POI", mappedBy="cities")
* #ORM\OrderBy({"position" = "ASC"})
*/
protected $pois;
and
class POI {
/**
* #ORM\ManyToMany(targetEntity="City", inversedBy="pois")
* #ORM\JoinTable(name="poi_cities")
*/
protected $cities;
I would like to fetch all POIs that have at least 1 association with some City using QueryBuilder. I should probably use exists() function but I don't quiet know how.
You'd have to Left join them and check if cities is null.
$qb->select('p', 'c')
->from('AcmeDemoBundle:POI', 'p')
->leftJoin('p.cities', 'c')
->where('c IS NOT NULL');
I haven't tested it, but I hope it gives you the general direction. You can read more about the QueryBuilder from here.
Docrine2 was changed in 2013, so the other solution displays error Error: Cannot add having condition on a non result variable. Now we cannot use joined alias just as a condition variable. We should use any of its properties like c.id
So you should fix the code to
$qb->select('p', 'c')
->from('AcmeDemoBundle:POI', 'p')
->leftJoin('p.cities', 'c')
->where('c.id IS NOT NULL');
$results = $qb->getQuery()->execute();
If you want to select entities that does not have any cities, use IS NULL.
$qb->leftJoin('p.cities', 'city')
->where('city.id IS NULL')
->getQuery()
->execute();
Description of a problem and link to the commit that responsible for that - http://www.doctrine-project.org/jira/browse/DDC-2780

Doctrine 2 - Find all entities in a repository except one with a particular id value

I'm using Doctrine 2.
I want to get all Entities of an entity class except for the one with id = 0.
I could use QueryBuilder like this:
// $em is EntityManager
$em->createQueryBuilder()
->select('c')
->from('Category', 'c')
->where('c.id <> 0')
->getQuery()
->getResult();
But looking at this code, it feels like too much for such a simple task.
I'm curious to know if there is any other simpler way in Doctrine for doing this.
Nop, that's how you should do it. You could omit query builder and pass entire DQL query:
$em->createQuery("SELECT c FROM Category c WHERE c.id != 0")->getResult();
It's not the better practice to pass the ID number, you might pass the Category object like this :
public function findAllExcept($category) {
$qb = $this->createQueryBuilder('Category');
$qb->add('select', 'c')
->add('from', 'Category c')
->add('where', 'c != :category')
->setParameter('category', $category);
return $qb->getQuery()->getResult();
}
For comparisons and conditions I recommend use Doctrine as well. It will save your time in case of switch between databases, for instance MySQL to PostgreSQL:
$this->createQueryBuilder()
->select('c')
->from('Category', 'c')
->where($qb->expr()->neq('c.id', '?1'))
->setParameter('1', $category)
->getQuery()
->getResult()

Categories