I'm trying to get a single row returned from a native query with Doctrine. Here's my code:
$rsm = new ResultSetMapping;
$rsm->addEntityResult('VNNCoreBundle:Player', 'p');
$rsm->addFieldResult('p', 'player_id', 'id');
$sql = "
SELECT player_id
FROM players p
WHERE CONCAT(p.first_name, ' ', p.last_name) = ?
";
$query = $this->getEntityManager()->createNativeQuery($sql, $rsm);
$query->setParameter(1, $name);
$players = $query->getResult();
That last line returns a list of players but I just want one result. How do I do that?
You can use $query->getSingleResult(), which will throw an exception if more than one result are found, or if no result is found. (see the related phpdoc here https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/AbstractQuery.php#L791)
There's also the less famous $query->getOneOrNullResult() which will throw an exception if more than one result are found, and return null if no result is found. (see the related phpdoc here https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/AbstractQuery.php#L752)
Both getSingleResult() and getOneOrNullResult() will throw an exception if there is more than one result.
To fix this problem you could add setMaxResults(1) to your query builder.
$firstSubscriber = $entity->createQueryBuilder()->select('sub')
->from("\Application\Entity\Subscriber", 'sub')
->where('sub.subscribe=:isSubscribe')
->setParameter('isSubscribe', 1)
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
->getSingleScalarResult() will return a single value, instead of an array.
I just want one result
implies that you expect only one row to be returned. So either adapt your query, e.g.
SELECT player_id
FROM players p
WHERE CONCAT(p.first_name, ' ', p.last_name) = ?
LIMIT 0, 1
(and then use getSingleResult() as recommended by AdrienBrault) or fetch rows as an array and access the first item:
// ...
$players = $query->getArrayResult();
$myPlayer = $players[0];
I use fetchObject() here a small example using Symfony 4.4
<?php
use Doctrine\DBAL\Driver\Connection;
class MyController{
public function index($username){
$queryBuilder = $connection->createQueryBuilder();
$queryBuilder
->select('id', 'name')
->from('app_user')
->where('name = ?')
->setParameter(0, $username)
->setMaxResults(1);
$stmUser = $queryBuilder->execute();
dump($stmUser->fetchObject());
//get_class_methods($stmUser) -> to see all methods
}
}
Response:
{
"id": "2", "name":"myuser"
}
To fetch single row
$result = $this->getEntityManager()->getConnection()->fetchAssoc($sql)
To fetch all records
$result = $this->getEntityManager()->getConnection()->fetchAll($sql)
Here you can use sql native query, all will work without any issue.
Related
I thought it would be a good idea to define a query and use it for several selects or counts later, but it does not work. The second select has both wheres in the sql statement:
$query = Pic::where('pics.user_id',$user->id);
if($cat) $query->where('cat',$cat);
if($year) $query->where('jahrprod',$year);
$zb = $query->select('pics.id','pics.title','pics.created_at')
->where('pics.id', '>', $pic->id)
->orderBy('pics.id')
->take(2)
->get()->reverse();
$za = $query->select('pics.id','pics.title','pics.created_at')
->where('pics.id', '<', $pic->id)
->orderBy('pics.id')
->take(13)
->get();
Query:
SELECT `pics`.`id`, `pics`.`title`, `pics`.`created_at`
FROM `pics`
WHERE `pics`.`user_id` = '3'
AND `pics`.`id` > '2180'
AND `pics`.`id` < '2180'
ORDER BY `pics`.`id` ASC, `pics`.`id` ASC
LIMIT 13
I tried to "pass it as reference" i.e. &$query->select... but "only variables can be passed as reference".
How can I use the query , or save it, and use it for both actions. Is it possible?
You are updating object state with the statements when you do $query->where(), so yeah, when you're doing a second select, all conditions from the first one are still there. Thats the reason why these lines work without any assignments:
if($cat) $query->where('cat',$cat);
if($year) $query->where('jahrprod',$year);
To achieve described behaviour you would need to create an query object copy:
$query = Pic::where('pics.user_id',$user->id);
if($cat) $query->where('cat',$cat);
if($year) $query->where('jahrprod',$year);
$queryClone = clone $query;
$zb = $query->select('pics.id','pics.title','pics.created_at')
->where('pics.id', '>', $pic->id)
->orderBy('pics.id')
->take(2)
->get()->reverse();
$za = $queryClone->select('pics.id','pics.title','pics.created_at')
->where('pics.id', '<', $pic->id)
->orderBy('pics.id')
->take(13)
->get();
Notice that mere assignment would not work here:
$queryClone = $query;
Because that would pass object reference and would result in the same behaviour as in your case. Clone creates a full object copy.
http://php.net/manual/en/language.oop5.cloning.php
I want to get one single value from entity.Can anyone help me here.
Here is my code.Please let me know what is missing here.
$query = $em->createQuery("SELECT e FROM AdminBundle:MailTemplates e WHERE e.keyword = '" .$keywordVal."'");
$query->execute();
$result = $query->getResult();
echo $result ->getId();
Here i want the 'id'.
This is noted in the documentation how you can do this.
So given you're code this will become:
$query = $em->createQuery("SELECT e.id FROM AdminBundle:MailTemplates e WHERE e.keyword = ?1");
$query->setParameter(1, $keywordVal);
$query->execute();
$result = $query->getResult(); // array of MailTemplates ids
Note: I also made use of setParameters instead of setting the value directly in the query.
In your controller:
$this->get('database_connection')->fetchColumn('select id from mail_templates where...');
That's much better for performance and much easier if you don't want to have a deal with query builder and other doctrine orm stuff.
Using the query builder you could do...
$queryBuilder = $em->createQueryBuilder('e');
$queryBuilder
->select('e.yourColumn')
// This will return just this column
// Alternatively you could omit any select to return the whole object
// that you could then use like $object->getYourColumn() if you so chose
->where($queryBuilder->expr()->eq('e.keyword', ':keyword'))
->setParameter('keyword', $keyword)
;
return $queryBuilder
->getQuery()
->getResult();
try this on loading Entities instead of creating own queries
Loading the entity with the Repository.
$rep = $this->getDoctrine()->getManager()->getRepository("Bundlename:Entity");
//find one by keyword -> single entity
$entity = $rep->findOneBy(array('keyword' => $keyword));
//find all by keyword - Array of entities
$result = $rep->findBy(array('keyword' => $keyword));
Before I begin, I believe I have tried everything from this previous post: How to use WHERE IN with Doctrine 2
So I have a Silex application connected to a MySQL DB using Doctrine via composer (doctrine/dbal 2.2.*)
The query builder I am trying to run is this:
$qb = $this->db->createQueryBuilder();
$stmt = $qb->select('DAY(datefield1) x, COUNT(*) value')
->from('table1', 's')
->join('s', 'table2', 't', 't.key=s.key')
->where('MONTH(datefield1) = :billMonth')
->andWhere('YEAR(datefield1) = :billYear')
->andWhere('t.key IN (:keylist)')
->groupBy('x')
->orderBy('x', 'asc')
->setParameter(':billMonth', $month)
->setParameter(':billYear', $year)
->setParameter(':keylist', implode(",", $keylist))
->execute();
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
The parameters are (month=8)(year=2014)(keylist=array(1,2,3,4))
The query does not fail but it curiously doesn't contain all the data that it should.
I have tried ->setParameter(':keylist', $keylist) to use the raw array, and this didn't work.
I have tried this kind of syntax too:
$qb->add('where', $qb->expr()->in('r.winner', array('?1')));
However that threw up an error because the in method wasn't available in expression builder class.
Please will someone cast an eye over this and save me from having to hardcode my SQL?
OK seeing as this old thread has seen some action since I last looked I wanted to confirm that the issue is long resolved - a third parameter in setParameter allows you to inform Doctrine how to handle the array:
$qb = $this->db->createQueryBuilder();
$stmt = $qb
->select('*')
->from(self::DB_TABLE, 'x')
->where('x.service IN (:services)')
->orderBy('x.session_end', 'DESC')
->addOrderBy('x.direction', 'DESC')
->setParameter(':services', $services, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
->setFirstResult($offset)
->setMaxResults($count)
->execute();
$result = $stmt->fetchAll(\PDO::FETCH_ASSOC);
DB placeholders/parameters are for single values. You're passing in a monolithic string 1,2,3,4 due to calling implode() on the array. Given:
WHERE t.key IN (:keylist)
then this query will be executed as the equivalent of
WHERE t.key IN ('1,2,3,4')
^-------^---note the quotes
Since it's a string, and only one single string in the IN clause, it's the functional equivalent of
WHERE t.key = '1,2,3,4'
and not the
WHERE (t.key = 1 OR t.key = 2 OR ....)
you want it to be. Either set up multiple parameters, one for each value in your array, or embed your string in the query directly
->andWhere('t.key IN (' . implode(',', $keylist) . ')')
which of course opens you up to sql injection attack vulnerabilities.
If you build the sql query yourself you can use DBAL's PARAM_INT_ARRAY type:
use Doctrine\DBAL\Connection as DB;
$db->executeQuery('SELECT DAY(datefield1) x, COUNT(*) value
FROM table1 s
JOIN table2 t ON t.key=s.key
WHERE MONTH(datefield1) = :billMonth
AND YEAR(datefield1) = :billYear
AND t.key IN (:keylist)
GROUP BY x
ORDER BY x ASC',
array(':billMonth' => $month, ':billYear' => $year, ':keylist' => $keylist),
array(':billMonth' => \PDO::PARAM_INT, ':billYear' => \PDO::PARAM_INT, ':keylist' => DB::PARAM_INT_ARRAY
)->fetchAll(\PDO::FETCH_ASSOC);
Correct way to handle such IN clause is as simple as it can be:
$qb = $this->db->createQueryBuilder();
$stmt = $qb->(...)
->andWhere('t.key IN (:keylist)')
->setParameter(':keylist', $keylist)
->getQuery()
->getArrayResult();
I have used this dozen times and it works - doctrine is smart enough to handle your $keylist being array.
Other thing is that I don't know why you're using fetchAll method which is reduntant here - execute() is just enough. Maybe this is a root of your problem.
My suggestion: try to fire action in dev mode (app_dev.php) and check your app/logs/dev.log - you will find all sql queries performed. Verify that database returns data which you are expecting from Doctrine.
->add('where', $qb->expr()->andX(
$qb->expr()->in('r.winner', ':winner')
))
->setParameters(array(
"winner" => $winners,
"billMonth", $month,
// add all params here
));
You should use the in expression via the querybuilder like below, and change how you set the parameter:
->andWhere($qb->expr()->in('t.key', ':keylist'))
The complete code:
$qb = $this->db->createQueryBuilder();
$stmt = $qb->select('DAY(datefield1) x, COUNT(*) value')
->from('table1', 's')
->join('s', 'table2', 't', 't.key=s.key')
->where('MONTH(datefield1) = :billMonth')
->andWhere('YEAR(datefield1) = :billYear')
->andWhere('t.key')
->andWhere($qb->expr()->in('t.key', ':keylist'))
->groupBy('x')
->orderBy('x', 'asc')
->setParameter(':billMonth', $month)
->setParameter(':billYear', $year)
->setParameter(':keylist', $keylist)
->execute();
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
I have in my table "Artiste" one column "valideAdmin" who takes value 1 or 0.
I try to make a simple count to return the number of entries in my table where "valideAdmin" is to 1:
$repo = $this ->getDoctrine()
->getManager()
->getRepository('ProjectMainBundle:Artiste');
$qb = $repo->createQueryBuilder('valideAdmin');
$qb->select('COUNT(valideAdmin)');
$qb->where('valideAdmin=1');
$count = $qb->getQuery()->getSingleScalarResult();
return array(
'count' => $count
);
But it always "1" who's return...
Without where clause, I have the total count of the entries of the table, but valideAdmin can be 0 or 1. I only want the count number where valideAdmin=1
Thanks for help
createQueryBuilder()'s first parameter is the alias that you want your entity to take (ie.: a short name to be used to refer to your entity in the query).
What you need to do is set a proper alias for your entity (for example a for Artiste) and then COUNT() the instances of your entity where the property (not the column) valideAdmin is set to one:
$repo = $this ->getDoctrine()
->getManager()
->getRepository('ProjectMainBundle:Artiste');
$qb = $repo->createQueryBuilder('a');
$qb->select('COUNT(a)');
$qb->where('a.valideAdmin = :valideAdmin');
$qb->setParameter('valideAdmin', 1);
$count = $qb->getQuery()->getSingleScalarResult();
Remember that DQL runs queries on entities. The DQL your write is then translated into SQL to query the underlying data source after.
Also you can fetch all date then use of COUNT function in PHP
This method has an advantage.You do not have to use a complex query.
You have all the information with count columns
$repositoryArtiste = $this->getDoctrine()
->getRepository('ProjectMainBundle:Artiste');
$queryArtiste= $repositoryArtiste->createQueryBuilder('a')
->Where('a.valideAdmin = :valideAdmin')
->setParameter('valideAdmin',1)
->getQuery();
$Artiste = $queryArtiste->getResult();
var_dump(count($Artiste));
I have the following code in my Symfony2 Repository Class...
$query = $this->createQueryBuilder('foo')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
How do I get the number of rows found by the database?
Thanks in advance
You need to execute DQL to do something you want.
$query = $this->createQueryBuilder()
->from('foo', 'f')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
$total = $query->select('COUNT(f)')
->getQuery()
->getSingleScalarResult();
I think you can do something like that:
$query = $this->createQueryBuilder()
->select('COUNT(f.id)')
->from('foo', 'f')
->where('foo.bar = :id')
->setParameter('id', $myID)
->getQuery();
$total = $query->getSingleScalarResult();
You execute the query then get the results. When you have the results, you get the number of record by doing a count on the results:
$results = $query->getResult();
$resultCount = count($results);
If you are concerned with paging, like getting 25 records out of the total. Then, you have two choices.
You perform the query twice, one time to get total results, another time to retrieve only 25 results using the method setFirstResult and setMaxResults. This method setFirstResult enable you to set the offset and the second, setMaxResults, number of records. The following code will give you results ranging from 25 to 50, it's the second page if you use 25 records by page.
$query->setFirstResult(25);
$query->setMaxResults(25);
You can check doctrine-extensions for Doctrine2 which have paginator support. These extensions have been made by one of the developer of Doctrine2. You can review these here.
Hope this help.
Regards,
Matt
I think this is as concise as it gets:
$qb = $repo->createQueryBuilder('entity');
$qb->select('COUNT(entity)');
$count = $qb->getQuery()->getSingleScalarResult();
Where $repo is of type Doctrine\ORM\EntityRepository