JOIN DQL SYMFONY - symfony

i want to count how many baby for a parent
class abonnementRepository extends \Doctrine\ORM\EntityRepository
{
public function SumEnfantDQL($id)
{
$entityManager = $this->getEntityManager();
$query = $entityManager->createQueryBuilder();
$query->select('sum(o.id) AS somme');
$query->from('AppBundle:enfant', 'o');
$query->join('AppBundle:User','p')->where('p.id = :id');
$rez = $query->getQuery()->getResult();
return $rez;
}
}
the entity enfant had matricul_prt and entity user had enfant_id and $id parameter is the parent id
i don't know how it work with join or innerJoin .So what i want to do is
SELECT SUM(*)
FROM enfant e
WHERE e.matricul_prt = $id;
Thank you so much

First of all, you should create a Repository class for AppBundle:enfant, this repo does not look like created fot 'enfant'.
Next the method should look like below, but only if there is valid association between 'enfant' and 'User'.
public function SumEnfant(int $id): int
{
return $this->createQueryBuilder('e') <- alias for 'enfant'
->select('sum(e.id)')
->join('e.user', 'u') <- join by entity property
->where('u.id = :id') <- condition for associated entity
->setParameter('id' , $id) <- parameter
->getQuery()
->getSingleScalarResult();
}
Try this, read doc once again and modify for your case.

Related

i need convert SQL query to Doctrine Query Builder

I have a relation ManyToMany and the tables in my databases are :
article : (id,titre,description,category,createAt)
article_groupe_auteur: (article_id,groupe_auteur_id)
groupe_auteur : (id,nom,prenom,adress,institution,city)
i need to to retrive the authors relied to an article.
Sql Query
use RevueProject;
select nom_auteur,prenom_auteur,nom_ins,adresse_ins from groupe_auteur ga
INNER JOIN
article_groupe_auteur aga on groupe_auteur.id = aga.groupe_auteur_id
INNER JOIN article a on aga.article_id = a.id
where a.id=21;
Dql Query
public function SelectArticleAuthors2(int $Id){
return $this->createQueryBuilder('GA');
->innerJoin('article_groupe_auteur','aga', Join::WITH , 'aga = ga.groupe_auteur_id')
->innerJoin('article','a',Join::WITH , 'a = aga.article_id')
->where('aga.article_id = : Id')
->setParameter('Id', $Id);
->getQuery()->getResult()
}
Its how i get the authors relied to an specify article by a relation ManyToMany
class GroupeAuteurRepository extends ServiceEntityRepository
{
/**
* #return mixed
*/
public function SelectArticleAuthors(int $id)
{
// ga (alias) : GroupeAuteur Entity
return $this->createQueryBuilder('ga')
// articles (collection)
->innerJoin('ga.articles','a','WITH','a.id=:id')
->setParameter('id', $id)
->getQuery()->getResult();
}
}

Doctrine hydrate not mapped field

I am making a query with Doctrine which calculates a custom field using a CASE WHEN like this:
public function findLatestPaginator($page = 1, $itemsPerPage)
{
$qb = $this->createQueryBuilder('n');
$qb = $qb
->select(['n AS news', 'CASE WHEN lu.id IS NOT NULL THEN 1 ELSE 0 END AS n.liked'])
->leftJoin('n.likingUsers', 'lu')
;
$qb = $qb
->orderBy('n.date', 'DESC')
->setFirstResult($itemsPerPage * ($page - 1))
->setMaxResults($itemsPerPage)
->getQuery()
;
return $qb->getResult();
}
In my entity I have a field called $liked which is not mapped. Is it possible to make the query (or the hydrator?) automatically set the field on the resulting entity?
Right now I am making a foreach loop and manually setting the property:
/**
* #return News[]
*/
private function convertNews(array $records)
{
$newsList = [];
foreach ($records as $record) {
if (isset($record['liked'], $record['news'])) {
/** #var News */
$news = $record['news'];
$news->liked = boolval($record['liked']);
$newsList[] = $news;
}
}
return $newsList;
}
Maybe a DTO could be useful here : doctrine documentation
Basically, you define a PHP class which is not mapped to your model.
You can then select what you need and trigger the instantiation of an object of this PHP class from the DQL query.
Hope this helps !
Default hydrator does not include unmapped properties (wow, right?).
You want to override/extend doctrine/orm/lib/Docrtrine/ORM/Internal/Hydration/AbstractHydrator
line 386 where it only checks for $classMetadata fieldMappings
Or you can hack around by using DTO and query in transformer, if performance is not needed

Symfony2 how to get entity alias in repository

i would like to write some DQL query in my entity repository function but instead of haroding entity alias into DQL i would like to get actual entity alias from repository.
my repository:
/**
* TrackingRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class TrackingRepository extends EntityRepository
{
public function test()
{
$dql = 'SELECT * FROM MyBundle:Tracking';
// i would like to call something like this:
// $dql = 'SELECT * FROM ' . $this->getEntityAlias;
$query = $this->getEntityManager()->createQuery($dql);
...
}
}
is this somehow possible?
You can get the entity class with $this->getClassName() in your repository :
class TrackingRepository extends EntityRepository
{
public function test()
{
$dql = 'SELECT t FROM ' . $this->getClassName() . ' t';
$query = $this->getEntityManager()->createQuery($dql);
...
}
}
class TrackingRepository extends EntityRepository
{
public function test()
{
$dql = 'SELECT t.property1,t.property2,t.property3,t.property4 FROM MyBundle:Tracking t';
// i would like to call something like this:
// $dql = 'SELECT * FROM ' . $this->getEntityAlias;
$query = $this->getEntityManager()->createQuery($dql);
...
}
}
What kind of query you want to execute? Are you realy need DQL? There are other ways to achive execute complex query, please consider:
Repository findBy($criteria):
public function test()
{
$this-> findBy($criteria);
}
For more complex queries you can also use:
Criteria and matching:
use Doctrine\Common\Collections\Criteria;
//
public function test()
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('sth', 'val'))
// more criteria here
$result = $this->matching($criteria);
}
Doctrine's Query Builder
Or even Query Builder with specific criteria expressions:
public function test()
{
$qb = $er->createQueryBuilder('p');
$qb
->where($qb->expr()->andx(
$qb->expr()->in('p', '?1'),
$qb->expr()->isNotNull('p.someField')
))
->setParameter(1, $someValue);
$result = $this->matching($criteria);
}

Using Count and Group By with Doctrine2 ,Symfony2 and AliDataBundle

I have an entity with three fields (id, user, location).
I want to display the number of users by location.
With SQL it's very easy, but I have an error when i want to use DQL and AliDatatableBundle
$qb = $this->createQueryBuilder('a')
->select("count(*) as myCount, a.location")->groupBy('a.location');
'myCount' does not point to a Class.
I've seen that AliDataBundle can use alias. It's should works.
Any Ideas ?
You can try this one in your entity repository:
public function getSth() {
$query = 'your sql query here';
$em = $this->getEntityManager();
$connection = $em->getConnection();
$stmt = $connection->prepare($query);
$stmt->execute();
return $stmt->fetchAll();
}
Or by query builder:
public function getSth() {
$qb = $this->createQueryBuilder();
$qb->select('count(a.id)');
$qb->from('YourBundleBundle:Entity','a');
$qb->groupBy('a.location');
$query = $qb->getQuery();
return $query->->execute();
}

FOS bundle - How to select users with a specific role?

I am using the FOS bundle and I want to retrieve all users with a given ROLE from the database.
What is the best way to do this?
Just add this in your UserRepository or replace $this->_entityName by YourUserBundle:User:
/**
* #param string $role
*
* #return array
*/
public function findByRole($role)
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from($this->_entityName, 'u')
->where('u.roles LIKE :roles')
->setParameter('roles', '%"'.$role.'"%');
return $qb->getQuery()->getResult();
}
If you are using FOSUser Groups you should use:
/**
* #param string $role
*
* #return array
*/
public function findByRole($role)
{
$qb = $this->_em->createQueryBuilder();
$qb->select('u')
->from($this->_entityName, 'u')
->leftJoin('u.groups', 'g')
->where($qb->expr()->orX(
$qb->expr()->like('u.roles', ':roles'),
$qb->expr()->like('g.roles', ':roles')
))
->setParameter('roles', '%"'.$role.'"%');
return $qb->getQuery()->getResult();
}
Well, if there is no better solution, I think I will go to a DQL query:
$query = $this->getDoctrine()->getEntityManager()
->createQuery(
'SELECT u FROM MyBundle:User u WHERE u.roles LIKE :role'
)->setParameter('role', '%"ROLE_MY_ADMIN"%');
$users = $query->getResult();
If you have this requirement and your user list will be extensive, you will have problems with performance. I think you should not store the roles in a field as a serialized array. You should create an entity roles and many to many relationship with the users table.
As #Tirithen states, the problem is that you will not get the users that have an implicit role due to role hierarchy. But there is a way to work around that!
The Symfony security component provides a service that gives us all child roles for a specific parent roles. We can create a service that does almost the same thing, only it gives us all parent roles for a given child role.
Create a new service:
namespace Foo\BarBundle\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Role\Role;
/**
* ReversedRoleHierarchy defines a reversed role hierarchy.
*/
class ReversedRoleHierarchy extends RoleHierarchy
{
/**
* Constructor.
*
* #param array $hierarchy An array defining the hierarchy
*/
public function __construct(array $hierarchy)
{
// Reverse the role hierarchy.
$reversed = [];
foreach ($hierarchy as $main => $roles) {
foreach ($roles as $role) {
$reversed[$role][] = $main;
}
}
// Use the original algorithm to build the role map.
parent::__construct($reversed);
}
/**
* Helper function to get an array of strings
*
* #param array $roleNames An array of string role names
*
* #return array An array of string role names
*/
public function getParentRoles(array $roleNames)
{
$roles = [];
foreach ($roleNames as $roleName) {
$roles[] = new Role($roleName);
}
$results = [];
foreach ($this->getReachableRoles($roles) as $parent) {
$results[] = $parent->getRole();
}
return $results;
}
}
Define your service for instance in yaml and inject the role hierarchy into it:
# Provide a service that gives you all parent roles for a given role.
foo.bar.reversed_role_hierarchy:
class: Foo\BarBundle\Role\ReversedRoleHierarchy
arguments: ["%security.role_hierarchy.roles%"]
Now you are ready to use the class in your own service. By calling $injectedService->getParentRoles(['ROLE_YOUR_ROLE']); you will get an array containing all parent roles that will lead to the 'ROLE_YOUR_ROLE' permission. Query for users that have one or more of those roles... profit!
For instance, when you use MongoDB you can add a method to your user document repository:
/**
* Find all users with a specific role.
*/
public function fetchByRoles($roles = [])
{
return $this->createQueryBuilder('u')
->field('roles')->in($roles)
->sort('email', 'asc');
}
I'm not into Doctrine ORM but I'm sure it won't be so different.
You can use just this on your DQL:
SELECT u FROM YourFavouriteBundle:User u WHERE u.roles [NOT] LIKE '%ROLE_YOUR_ROLE%'
Of course with QueryBuilder it's more elegant:
// $role = 'ROLE_YOUR_ROLE';
$qb->where('u.roles [NOT] LIKE :role')
->setParameter('role', "%$role%");
Finally i solved it, following is an exact solution:
public function searchUsers($formData)
{
$em = $this->getEntityManager();
$usersRepository = $em->getRepository('ModelBundle:User');
$qb = $usersRepository->createQueryBuilder('r');
foreach ($formData as $field => $value) {
if($field == "roles"){
$qb->andWhere(":value_$field MEMBER OF r.roles")->setParameter("value_$field", $value);
}else{
$qb->andWhere("r.$field = :value_$field")->setParameter("value_$field", $value);
}
}
return $qb->getQuery()->getResult();
}
Cheers!
In case you need to filter users by role using a DQL filter in a YAML file (In EasyAdminBundle for instance)
entities:
Admin:
class: App\Entity\User
list:
dql_filter: "entity.roles LIKE '%%ROLE_ADMIN%%'"
Here I give an alternative solution :
I find users of roles for a given array
In controller I call the function like that
$users = $userRepository->findUsersOfRoles(['ROLE_ADMIN', 'ROLE_SUPER_USER']);
Then in my repository I make a loop to generate condition and set the parameters :
public function findUsersOfRoles($roles)
{
$condition = 'u.roles LIKE :roles0';
foreach ($roles as $key => $role){
if ($key !== 0){
$condition .= " OR u.roles LIKE :roles".$key;
}
}
$query = $this->createQueryBuilder('u')
->where($condition);
foreach ($roles as $key => $role){
$query ->setParameter('roles'.$key, '%"'.$role.'"%');
}
return $query->getQuery() ->getResult();
}

Resources