Get unjoined values with dql - symfony

how can i get the unjoined values with dql ?
The problem in this code is that i'm getting only posts that have comments ..
public function getAllPostsDQL()
{
$q = $this->getEntityManager()
->createQuery('SELECT p.type,p.date,p.urlImage,p.nom,u.nom as nomU,u.prenom as prenomU ,COUNT(co) as nb,MAX(co.date) as maxDate FROM PidevBundle:Publication p LEFT OUTER JOIN
PidevBundle:Commentaire co WITH co.idPublication=p
JOIN PidevBundle:User u WITH p.idUser=u
');
return $q->getResult();
}

Try this: (for Symfony3 syntax may need to be changed)
public function getAllPostsDQL()
{
$qb = $this->createQueryBuilder('publication');
$qb->select(array('publication.type', 'publication.date', 'publication.urlImage',
'publication.nom', 'u.nom AS nomU', 'u.prenom AS prenomU',
'COUNT(co.id) AS nb', 'MAX(co.date) AS maxDate'))
->leftJoin('p.idUser', 'u')
->leftJoin('p.idCommentaire', 'co');
return $qb->getQuery()->getResult();
}

Try something like this:
public function getAllPostsDQL()
{
$q = $this->getEntityManager()->createQuery(
'SELECT
p.type,
p.date,
p.urlImage,
p.nom,
u.nom as nomU,
u.prenom as prenomU,
COUNT(co.id) as nb,
MAX(co.date) as maxDate
FROM PidevBundle:Publication p
LEFT JOIN p.idUser u
LEFT JOIN PidevBundle:Commentaire co ON co.id = u.id
');
return $q->getResult();
}

I have finally found a solution for it , although i think it's a trash code :/
Thanks for everyone .
Code :
public function getAllPostsDQL()
{
$q = $this->getEntityManager()->createQuery(
'SELECT
p.type,
p.date,
p.urlImage,
p.nom,
u.nom as nomU,
u.prenom as prenomU,
(SELECT COUNT(co.id) FROM PidevBundle:Commentaire co WHERE co.idPublication=p) as nb,
(SELECT MAX(com.date) FROM PidevBundle:Commentaire com WHERE com.idPublication=p) as maxDate
FROM PidevBundle:Publication p
INNER JOIN p.idUser u
');
return $q->getResult();
}

Related

Symfony custom repository query giving error

I am really new at Symfony and I am trying to get used to query builder. At the moment I am trying to join three tables and the following MySQL query gives me the results I need when I run it in PhpMyAdmin
SELECT * FROM pe_users u
LEFT JOIN pe_apply a ON u.id = a.user
LEFT JOIN pe_offer o ON a.id = o.application
However when I move this inside a Symfony Repository method
namespace Ache\AdminBundle\Repository;
use Doctrine\ORM\EntityRepository;
class AdminRepository extends EntityRepository{
public function findAllAppByStatus(){
$query = $this->getEntityManager()->createQuery(
'SELECT * FROM pe_users u
LEFT JOIN pe_apply a ON u.id = a.user
LEFT JOIN pe_offer o ON a.id = o.application
');
try {
return $query->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
}
I get the error
[Syntax Error] line 0, col 7: Error: Expected IdentificationVariable |
ScalarExpression | AggregateExpression | FunctionDeclaration |
PartialObjectExpression | "(" Subselect ")" | CaseExpression, got '*'
What does this error mean? what am I doing wrong?
UPDATE
The three entities I have are as following
UserBundle:User
CoreBundle:Apply
AdminBundle:Offer
User.id links with Apply.user and Offer.application links with Apply.id
You can still use raw sql with Symfony if you are comfortable with that
$conn = $this->getEntityManager()->getConnection();
$sql = "SELECT * FROM pe_users u LEFT JOIN pe_apply a ON u.id = a.user LEFT JOIN pe_offer o ON a.id = o.application WHERE u.id = a.user";
$stmt = $conn->prepare($sql);
$stmt->execute();
return $stmt->fetchAll();
I would do :
public function findAllAppByStatus(){
$qb = $this->createQueryBuilder('u')
->leftJoin('CoreBundle:Apply', 'a', 'WITH', 'a.user = u')
->leftJoin('AdminBundle:Offer', 'o', 'WITH', 'o.application = a')
->setMaxResults(1); // if you return only 1 result, you want to be sure only one (or none) result is fetched
return $qb->getQuery()->getOneOrNullResult();
if you want to return possibly many results, as the 'All' in the method name suggests, get rid of the ->setMaxResults() and use $qb->getQuery()->getResult();
see how the queryBuilder works with objects, not tables. Joins are built on entities and properties, not tables and field names.

Symfony 2: knppaginator does not allow left join

I use knppaginator for getting paginated results. When I use a LEFT JOIN statement in my query, I get the following error:
Cannot count query which selects two FROM components, cannot make distinction
The code in my controller looks like this:
public function paginationAction()
{
$em = $this->get('doctrine.orm.entity_manager');
$dql = "SELECT p.name, c.name
FROM MyBundle:Products p
LEFT JOIN MyBundle:Categories c
WITH c.id = p.categoryId";
$query = $em->createQuery($dql);
$request = $this->getRequest();
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query,
$request->query->getInt('page', 1),
10
);
$viewData['pagination'] = $pagination;
return $this->render('MyBundle:results.html.twig', $viewData);
}
How can I make the LEFT JOIN statement work? When I leave out the LEFT JOIN, everything works fine.
This question is asked before. Check out this answer: Doctrine : Pagination with left Joins

How to count Users by Pathology using DQL

I have an issue to find an alternative way to count Users who suffer a pathology (a count with a group by)
the issue is I prefer not to make a for loop on pathologies to count that, and I'de like if I could get your advice.
here's some pieces of code I have :
User Entity :
/**
* #ORM\OneToMany(targetEntity="Hospitalisation", mappedBy="user")
*/
private $hospitalisations;
Hospitalisation Entity:
/**
* #ORM\ManyToOne(targetEntity="Pathologie", inversedBy="hospitalisations")
*/
private $pathologie;
Pathology Entity:
/**
* #ORM\OneToMany(targetEntity="Hospitalisation", mappedBy="pathologie")
*/
private $hospitalisations;
What I have to do is to count how many users suffers of each pathologie in the database.
Thank you :)
Create a custom repository class PathologieRepository
http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
Add this (not tested):
public function countUsers($pathologieID)
{
$result = $this->getEntityManager()
->createQuery("
SELECT COUNT(u) as c FROM YourMainBundle:Users u
JOIN u.hospitalisations h
JOIN h.pathologies p
WHERE
p.id = :pathologie
")
->setParameter('pathologie', $pathologieID)
->setMaxResults(1)
->getSingleResult();
return $result['c'];
}
If you want do this in twig like (pseudo):
for pathologie as p
print p.countUsers(p.id)
You have to create a method in your pathologie entity class. But you cannot use entity manager in entity classes (you can by using a hack but this is not recommended). So you have to use loops to count the users.
public function getUserCount()
{
$hospitalisations = $this->getHospitalisations();
$counter = 0;
foreach ($hospitalisations as $h)
{
$counter += count($h->getUsers());
}
return $counter;
}
I solved the issue.
Here's the solution i've come up with:
$result = $this->getEntityManager()
->createQuery("
SELECT p.id, p.nom, COUNT(DISTINCT u) as nbUsers , COUNT(DISTINCT i) as nbImported
FROM AcmeDemoBundlePathologie p
left JOIN p.importedUsers i
left JOIN p.hospitalisations h
left JOIN h.user u
GROUP BY p.id, p.nom
")
->getArrayResult();

Symfony2: Doctrine subquery in the WHERE clause including a LIMIT

I'm trying to convert this SQL into either DQL or whatever the query builder variant would look like.
select *
from project_release r
where (select s.title as status_name
from release_status_log l
left join release_status s
on l.release_status_id = s.id
where l.release_id = r.id
order by l.created_at desc
limit 1
) not in ('Complete', 'Closed')
;
From inside the repository class for the Release entity, I've tried this
return $this->getEntityManager()->createQuery("
select r.*
from MyBundle:Release r
where (select s.title
from MyBundle:ReleaseStatusLog l
join l.status s
where l.release = r
order by l.createdAt desc
limit 1
) IN ('Complete','Closed')
order by r.release_date ASC
limit 10
")->getArrayResult();
Which gives the error
[Syntax Error] line 0, col 265: Error: Expected
Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got 'limit'
Which is referring to the limit 1 in the subquery.
So then I tried this
return $this
->createQueryBuilder('r')
->select('r.*')
->where("(select s.title
from MyBundle:ReleaseStatusLog l
join l.status s
where l.release = r
order by l.created_at desc
limit 1
) $inClause ('Complete', 'Closed')
")
->setMaxResults( $limit )
->orderBy('release_date', 'ASC')
->getQuery()
->getArrayResult()
;
Which gives the same error. How can I execute a subquery limited to 1 row per row in the parent query?
Symfony 2.0.15
Doctrine 2.1.7
PHP 5.3.3
MySQL 5.1.52
I have a solution for this now. I ended up falling back on the native query system with the result set mapping from the entity in questions.
It's not a great solution, but it works and until I see another solution, it's the only option with this type of WHERE clause.
Here's what my finder method looks like now
/**
* Finds Releases by their current status
*
* #param array $statuses White-list of status names
* #param boolean $blackList Treat $statuses as a black-list
* #param integer $limit Limit the number of results returned
* #param string $order Sort order, ASC or DESC
*
* #throws \InvalidArgumentException
*
* #return array <Release>
*/
public function findByCurrentStatus( array $statuses, $blackList=false, $limit=null, $order='ASC' )
{
if ( empty( $statuses ) )
{
throw new \InvalidArgumentException( "Must provide at least one status" );
}
$inClause = $blackList ? 'not in' : 'in';
$rsm = new ResultSetMappingBuilder($this->getEntityManager());
$rsm->addRootEntityFromClassMetadata('MyBundle:Release', 'r');
$SQL = "
select *
from project_release r
where (select s.title as status_name
from release_status_log l
left join release_status s
on l.release_status_id = s.id
where l.release_id = r.id
order by l.created_at desc
limit 1
) $inClause ('" . implode( "','", $statuses ) . "')
order by r.release_date $order
";
if ( $limit )
{
$SQL .= " limit $limit";
}
return $this
->getEntityManager()
->createNativeQuery( $SQL, $rsm )
->getResult()
;
}
I kind of loathed going back to building a query as a string, but oh well. Oh, and for you eagle-eyes, $statuses does not come from user data, so no SQL injection vulnerabilities here ;)
In addition to your Native SQL solution, you can create two queries using DQL within a single repository method.
Some adjustment may be required but you could try this:
public function findCompletedReleases()
{
$em = $this->getEntityManager();
$dqlSubQuery = <<<SQL
SELECT
s.title status_name
FROM
Acme\MyBundle\Entity\ReleaseStatus s,
Acme\MyBundle\Entity\ReleaseStatusLog l,
Acme\MyBundle\Entity\Release r
WHERE
l.release = r.id AND
l.status = s.id
ORDER BY l.createdAt DESC
SQL;
$statusName = $em->createQuery($dqlSubQuery)
->setMaxResults(1)
->getSingleScalarResult();
$dql = <<<SQL
SELECT
r
FROM
Acme\MyBundle\Entity\Release r
WHERE
:status_name IN ('Complete','Closed')
ORDER BY r.release_date ASC
SQL;
$q = $em->createQuery($dql)
->setParameters(array('status_name' => $statusName))
->setMaxResults(10);
return $q->getArrayResult();
}

query with dateformat in where clause in symfony2

when I run a query with date in where clause, following error is showed...
[Syntax Error] line 0, col 129: Error: Expected known function, got 'DATE_FORMAT'
the query is given below
$query = $this->getEntityManager()->createQuery(
"SELECT a.id, a.amont, a.paymentDescrip, a.paymentType, a.paymentDate
FROM RegalSmsBundle:DailyTransaction a
WHERE DATE_FORMAT(a.paymentDate,'%Y-%m-%d') = :paymentDate
and a.students = :studentId"
)->setParameter('studentId', $studentId)
->setParameter('paymentDate','2013-03-11');
return $query->getResult();
Doctrine doesn't have DATE_FORMAT function defined by default. It's possible to Register Custom DQL Function.
But you can compare date easily (assuming a.paymentDate is of type date):
$query = $this->getEntityManager()->createQuery("
SELECT a.id, a.amont, a.paymentDescrip, a.paymentType, a.paymentDate
FROM RegalSmsBundle:DailyTransaction a
WHERE a.paymentDate = :paymentDate AND a.students = :studentId
")
->setParameter('studentId', $studentId)
->setParameter('paymentDate', new \DateTime('2013-03-11'))
;
return $query->getResult();
Edit: I prefer using querybuider to writing DQL. It would look like this:
$qb = $this->getEntityManager()->getRepository('RegalSmsBundle:DailyTransaction')->createQueryBuilder('a');
$qb
->select('a') // select whole entity
->where($qb->expr()->andX(
$qb->expr()->eq('a.paymentDate', ':paymentDate')
$qb->expr()->eq('a.students', ':studentId')
))
->setParameter('studentId', $studentId)
->setParameter('paymentDate', new \DateTime('2013-03-11'))
;
return $qb->getQuery()->getResult();

Resources