Doctrine dql manytomany query to pre fetch foreighn entitties - php

I have a User entity and Role entity. A user can have many roles and a role can have many users. The parts that matter (I think) are the following:
In User.php
/**
* #ORM\ManyToMany(targetEntity="Role",inversedBy="users")
* #ORM\JoinTable(name="user_role",
* joinColumns={#ORM\JoinColumn(name="userid", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="roleid", referencedColumnName="id")}
* )
*/
protected $roles;
public function __construct(){
$this->roles = new ArrayCollection();
}
In Role.php:
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="roles")
* #ORM\JoinTable(name="user_role",
* joinColumns={#ORM\JoinColumn(name="roleid", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="userid", referencedColumnName="id")}
* )
*/
protected $users;
public function __construct(){
$this->users = new ArrayCollection();
}
Trying the following query gives me a User that gets it's id and name field replaced with Role id and name
$result = $this->getEntityManager()->createQuery('SELECT
u.id, u.username, u.name, u.email, r.id, r.name
FROM mytestBundle:User u
LEFT JOIN u.roles r
WHERE u.id = :id')
->setParameter('id', $id)
->getArrayResult();
The following gives me an error: Error: Cannot select entity through identification variables without choosing at least one root entity alias.
$result = $this->getEntityManager()->createQuery('SELECT
u.id, u.name, r
//... rest is same
The following gives me the result as I expect but includes too many user fields. One user watching the profile of another user can't see the user's email, password, salt, ... but is allowed to see the user's roles:
$result = $this->getEntityManager()->createQuery('SELECT
u, r
So the question is: How do I select only certain user fields and have doctrine nest Roles in a user record without it throwing an error?

Posted too early, sorry.
This errors is quite common and many SO answers do not apply to my situation but this one does.
Using partial solved my problem:
$result = $this->getEntityManager()->createQuery('SELECT
partial u.{id, name}, r

Related

Symfony subquery for entity

Have a problem with subquery with symfony.
What I try to do - I have a table with users and a table with posts.
Posts Users
id|author|content id|username
I want create subquery to get user name by id.
/**
* #return array
*/
public function findAll()
{
return $this->getEntityManager()->createQuery(
'SELECT a, (SELECT u.username
FROM BackendBundle:User u WHERE u.id = a.author) as authorName
FROM BackendBundle:Article a'
)->getResult();
}
Result:
What am I doing wrong? What is the best way to join column from other table by id? Maybe i can use annotations?
Thx for any help.
You don't need a subquery here, what you need is a simple (INNER) JOIN to join Users with their Articles.
$em->createQuery("SELECT a FROM Article JOIN a.author'");
You don't even need an on clause in your join, because Doctrine should already know (through annotations on your entities or a separate yaml file), that the article.author field relates to user.id.
Edit:
I assume you have a User entity that is One-To-Many related to the Article entity.
class User
{
// ...
/**
* #OneToMany(targetEntity="Article", mappedBy="author")
*/
private $articles;
// ...
}
class Article
{
// ...
/**
* #var User
* #ManyToOne(targetEntity="User", inversedBy="articles")
*/
private $author;
// ...
}
Please refer to doctrines association mapping documentation: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html

Doctrine2 QB – how to select entities where OnetoOne entity doesn't exists

I have two entities:
class User extends BaseEntity {
/**
* #ORM\OneToOne(targetEntity="Profile", mappedBy="user", cascade={"persist", "remove"})
* #var Profile
*/
protected $profile;
}
class Profile extends BaseEntity {
/**
* #ORM\OneToOne(targetEntity="User", inversedBy="profile", cascade={"persist"})
* #ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")
* #var User
*/
protected $user;
}
What I'm trying to do is to SELECT only users who don't have any profile (so there's no profile row with user_id=:user_id in profiles table). However, I have no idea how to make my QueryBuilder.
First, I tried something simple like
//u as user
$query = $this->er->createQueryBuilder('u');
$query
->join('u.profile', 'p')
->where('u.profile = 1');
But that returns A single-valued association path expression to an inverse side is not supported in DQL queries. Use an explicit join instead. so I suppose there's something wrong with my relationship? I tried to switch join() for leftJoin() but it didn't help either...
So what's up with this error and how to make proper condition with where() to tell Doctrine I want only users where there's no profile?
Here is how I was able to do it. Basically I had Domain & Hosting entities and I wanted to select Domains that had no Hosting attached to them in a one to one relationship.
$er->createQueryBuilder('d')
->leftJoin('d.hosting', 'h')
->where('h.id is NULL');
Credits for this solution goes to this Answer
Hope it works for you since our situations are almost identical.
Just check for null as value of profile
//u as user
$query = $this->er->createQueryBuilder('u');
$query
->where('u.profile is NULL');
Try to use repositories, example for UserRepository:
$qb = $this->createQueryBuilder('u');
$e = $qb->expr();
$qb->leftJoin('u.profile', 'p')
->where($e->isNull('p.id'))
Raw query will look like this:
SELECT * FROM users AS u LEFT JOIN u.profile AS p WHERE p.id IS NULL;

Join DQL when intermediate table has not entity mapped

I'm building a repository method to look if a fos_group is assigned to any fos_user before allowing group to be deleted. Basically this is the raw query I'm trying to make using DQL:
SELECT
COUNT(*)
FROM
fos_user u
LEFT JOIN fos_user_user_group fug ON (fug.user_id = u.id)
WHERE
fug.group_id = :group_id
This is how I setup the relationship between Users and Groups:
/**
* #ORM\ManyToMany(targetEntity="Group")
* #ORM\JoinTable(name="fos_user_user_group",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
And this is what I have done til now:
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('COUNT(gr.id)')
->from("UserBundle:Group", "gr");
return $qb->getQuery()->getSingleScalarResult();
But I'm stuck since I do not know how to add the join sentence with not mapped table/entity (fos_user_user_group), can anyone give me some push?
You have mapped your property there you are in right way just join the property $groups in user entity it will join your junction table fos_user_user_group and the use what ever you where clause is
$qb
->select('COUNT(g.id)')
->from('UserBundle:User', 'u')
->join('u.groups g')
->where('g.id = :val')
->setParameter('val',$your_group_id);

Select many to many entity collection using DQL

I have to entities that have ManyToMany relation with linking table. Like this:
class User
{
/**
* #ORM\ManyToMany(targetEntity="Post")
* #ORM\JoinTable(name="favorite_posts",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="post_id", referencedColumnName="id")}
* )
**/
private $favoritePosts;
}
class Post
{
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="favoritePosts")
*/
private $usersInFavorite;
}
And I can get all user's favorite posts using a User entity object:
$favorites = $user->getFavoritesPosts();
But I have no idea how to get EXACTLY THE SAME result using DQL or Doctrine Query Builder. Under result i mean an array of POST entity objects.
Based on this exemple
If you want to fetch it by dql,
$dql = "SELECT p FROM Posts p INNER JOIN p.$usersInFavorite u WHERE u= ?1";
$query = $entityManager->createQuery($dql)
->setParameter(1, $user);
$favoritePosts = $query->getResult();
I tested it this time and i found the results as requested.
if you have the id of the user entity instead of the entity the same code will work with $user being the id of the user.

findBy with JOIN criteria in Symfony2

I have 3 simple tables: user, role, user_x_role with Many-To-Many relation. I have 2 entities: User and Role. User entity has $userRoles property with relation annotation. In Controller I need to fetch all users with specific role. But I don't know how to use JOIN in controller. Current wrong code:
$role = $this->getDoctrine()->getRepository('TestBackEndBundle:Role');
$roles = $role->findBy(array('name' => 'ROLE_PARTNER'));
$user = $this->getDoctrine()->getRepository('TestBackEndBundle:User');
$partners = $user->findBy(array('userRoles' => $roles));
It thows "Undefined index: joinColumns in ...". But I have joinColumns in User entity:
/**
* #ORM\ManyToMany(targetEntity="Role")
* #ORM\JoinTable(name="user_x_role",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE", onUpdate="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="role_id", referencedColumnName="id", onDelete="CASCADE", onUpdate="CASCADE")}
* )
* #var ArrayCollection
*/
protected $userRoles;
IMO the best way for it is create your own repository for User entity. Then in that repository create method like "getUsersByRole" where you make the query you want with query builder.
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('u')
->from('\namespace\for\User', 'u')
->join('u.roles', 'r')
->where(...)
return $qb->getQuery()->getResult();

Categories