I want to create a query that values more precise search terms, e.g. search for "Essen" should return Essen currently it returns Evessen as this is a valid value as well.
My current function:
public function findCities($city){
$qb = $this->createQueryBuilder('z');
$qb
->select('z')
->where($qb->expr()->like('z.city', ':city'))
->orderBy('z.code')
->setParameter('city', '%'.$city . '%');
return $qb->getQuery()->getResult();
}
Based on THIS advice I created a repository function:
public function findCities($city){
$qb = $this->createQueryBuilder('z');
$qb
->select('z')
->where($qb->expr()->like('z.city', ':city'))
->orderBy('INSTR(z.city, '.$city.'), z.city')
->setParameter('city', '%'.$city . '%');
return $qb->getQuery()->getResult();
}
Unfortunately it returns [Syntax Error] line 0, col 70: Error: Expected known function, got 'INSTR'
Any other approach (that does NOT return an array, as there is a function that needs heavy altering if the output is an array, I'd like to avoid that) maybe?
There is no INSTR function in DQL, that's why you get this error see docs
instead you can make NativeQuery see docs
something like this
$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
$rsm->addEntityResult('City', 'c');
// for every selected field you should do this
$rsm->addFieldResult('c', 'id', 'id');
$rsm->addFieldResult('c', 'name', 'name');
$em = $this->getEntityManager()
->createNativeQuery('
SELECT
id, name
FROM cities WHERE city LIKE '%:city%'
ORDER BY INSTR(city, ':city'), city',
$rsm
)->setParameter('city', $city);
return $em->getResult();
Related
An application has a page of statistics representing dozens of calculations. To avoid duplicating code in a repository the error
Error: 'c' is used outside the scope of its declaration
occurs when attempting to insert DQL with conditions into a QueryBuilder.
The basic entities include Household and Contact. Calculations are based on contact date range, site (location of contact), and type (type of contact). There is a service that creates an array of where clauses and query parameters, as will be evident in the code below.
I know the calculation works if all the code occurs in a single function. It seems the problem arises from the join with the Contact entity and its necessary constraints. Can DRY be accomplished in this scenario?
All of the following appear in the Household entity's repository.
The DQL is:
private function reportHousehold($criteria)
{
return $this->createQueryBuilder('i')
->select('i.id')
->join('TruckeeProjectmanaBundle:Contact', 'c', 'WITH',
'c.household = i')
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->getDQL()
;
}
Example of $criteria: $criteria['betweenWhereClause'] = 'c.contactDate BETWEEN :startDate AND :endDate'
One of the calculations on Household:
public function res($criteria)
{
$parameters = array_merge(
$criteria['betweenParameters'], $criteria['siteParameters'],
$criteria['startParameters'], $criteria['startParameters'],
$criteria['contactParameters']);
$qb = $this->getEntityManager()->createQueryBuilder();
return $this->getEntityManager()->createQueryBuilder()
->select('h.id, 12*(YEAR(:startDate) - h.arrivalyear) + (MONTH(:startDate) - h.arrivalmonth) Mos')
->from('TruckeeProjectmanaBundle:Household', 'h')
->distinct()
//DQL inserted here:
->where($qb->expr()->in('h.id', $this->reportHousehold($criteria)))
->andWhere($qb->expr()->isNotNull('h.arrivalyear'))
->andWhere($qb->expr()->isNotNull('h.arrivalmonth'))
->andWhere($criteria['startWhereClause'])
->setParameters($parameters)
->getQuery()->getResult()
;
}
You're either missing getRepository() or from()
Try this (my prefered choice) :
private function reportHousehold($criteria) {
return $this->getEntityManager
->createQueryBuilder()
->select("i.id")
->from(YourEntity::class, "i")
->join("TruckeeProjectmanaBundle:Contact", "c", "WITH", "c.household=i.id")
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->getQuery()
->execute();
}
Or this
private function reportHousehold($criteria) {
return $this->getEntityManager
->getRepository(YourEntity::class)
->createQueryBuilder("i")
->select("i.id")
->join("TruckeeProjectmanaBundle:Contact", "c", "WITH", "c.household=i.id")
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->getQuery()
->execute();
}
Careful, I'm assuming you're on Symfony 3 or above.
If not, replace YourEntity::class by Symfony 2 syntax which is "YourBundle:YourEntity"
In a sense Preciel is correct: the solution does require the use of $this->getEntityManager()->createQueryBuilder(). Instead of injecting DQL as a subquery, the trick is to return an array of ids and use the array in an IN clause. The effect is to remove any consideration of entities other than the Household entity from the calculation. Here's the result:
public function res($criteria)
{
$parameters = array_merge($criteria['startParameters'], $criteria['startParameters'], ['hArray' => $this->reportHousehold($criteria)]);
$qb = $this->getEntityManager()->createQueryBuilder();
return $this->getEntityManager()->createQueryBuilder()
->select('h.id, 12*(YEAR(:startDate) - h.arrivalyear) + (MONTH(:startDate) - h.arrivalmonth) Mos')
->from('TruckeeProjectmanaBundle:Household', 'h')
->distinct()
->where('h.id IN (:hArray)')
->andWhere($qb->expr()->isNotNull('h.arrivalyear'))
->andWhere($qb->expr()->isNotNull('h.arrivalmonth'))
->setParameters($parameters)
->getQuery()->getResult()
;
}
private function reportHousehold($criteria)
{
$parameters = array_merge($criteria['betweenParameters'], $criteria['siteParameters'], $criteria['contactParameters']);
return $this->createQueryBuilder('i')
->select('i.id')
->join('TruckeeProjectmanaBundle:Contact', 'c', 'WITH', 'c.household = i')
->where($criteria['betweenWhereClause'])
->andWhere($criteria['siteWhereClause'])
->andWhere($criteria['contactWhereClause'])
->setParameters($parameters)
->getQuery()->getResult()
;
}
I have an entity that has a column "inventoryLcoation_id" that has a many to one relationship. For some reason when I use createQueryBuilder() it is not returning that value in my ajax call, but it returns everything else: id, name, etc etc.. This is not an issue with Symfony2, its an issue with my lack of knowledge :)
Here is my query builder code:
$qb = $this
->createQueryBuilder('p')
->select('p.id', 'p.name')
->where('p.inventoryLocation = :inventoryId')
->andWhere('p.account = :account_id')
->setParameter('inventoryId', $value)
->setParameter('account_id', $account_id)
->orderBy('p.id', 'DESC');
if($qb->getQuery()->getArrayResult()){
return $qb->getQuery()->getArrayResult();
}else{
return false;
}
What do I need to code to have it also include the value from the inventoryLocation table which is mapped to the column value "inventoryLocation_id"?
Thanks so much for your help in enlightening my understanding to the awesome world of Symfony2!
try a join:
$qb->join('p.inventoryLocation','i')
and in the select especify both entities
$qb->select('p','i')
it should look like this:
$qb = $this
->createQueryBuilder('p')
->select('p','i')
->join('p.inventoryLocation','i')
->where('p.inventoryLocation = :inventoryId') // or ->where('i = :inventoryId')
->andWhere('p.account = :account_id')
->setParameter('inventoryId', $value)
->setParameter('account_id', $account_id)
->orderBy('p.id', 'DESC');
I am trying to filter out admins that have a super admin role. Why is the following not working?
public function findAdmins()
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('a')
->from('MyBundle:Admin', 'a')
->where($qb->expr()->notIn('ROLE_SUPER_ADMIN', 'a.roles'));
$result = $qb->getQuery()->execute();
return $result;
}
It will give me the following error:
[Syntax Error] line 0, col 68: Error: Expected Literal, got 'a'
The DQL-query looks like this:
SELECT a FROM MyBundle:Admin a WHERE ROLE_SUPER_ADMIN NOT IN(a.roles)
Role itself is not an entity. It is simply an array of strings.
$roles = array('ROLE_ADMIN', 'ROLE_SUPER_ADMIN)'
Try use MEMBER OF operator
$qb
->select('a')
->from('MyBundle:Admin', 'a')
->where(':role NOT MEMBER OF ad.roles')->setParamete('role', 'ROLE_SUPER_ADMIN');
Update.
The only solution found is to check serialized string in db with LIKE. Details here
Don't mix column name with table name
Try this,
$qb
->select('a')
->from('MyBundle:Admin', 'ad')
->where($qb->expr()->notIn('ROLE_SUPER_ADMIN', 'ad.roles'));
It should be like,
SELECT a FROM MyBundle:Admin ad WHERE ROLE_SUPER_ADMIN NOT IN(ad.roles)
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.
I have this symfony code where it retrieves all the categories related to a blog section on my project:
$category = $catrep->createQueryBuilder('cc')
->Where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->getQuery();
$categories = $category->getResult();
This works, but the query includes duplicates:
Test Content
Business
Test Content
I want to use the DISTINCT command in my query. The only examples I have seen require me to write raw SQL. I want to avoid this as much as possible as I am trying to keep all of my code the same so they all use the QueryBuilder feature supplied by Symfony2/Doctrine.
I tried adding distinct() to my query like this:
$category = $catrep->createQueryBuilder('cc')
->Where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->distinct('cc.categoryid')
->getQuery();
$categories = $category->getResult();
But it results in the following error:
Fatal error: Call to undefined method Doctrine\ORM\QueryBuilder::distinct()
How do I tell symfony to select distinct?
This works:
$category = $catrep->createQueryBuilder('cc')
->select('cc.categoryid')
->where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->distinct()
->getQuery();
$categories = $category->getResult();
Edit for Symfony 3 & 4.
You should use ->groupBy('cc.categoryid') instead of ->distinct()
If you use the "select()" statement, you can do this:
$category = $catrep->createQueryBuilder('cc')
->select('DISTINCT cc.contenttype')
->Where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->getQuery();
$categories = $category->getResult();
you could write
select DISTINCT f from t;
as
select f from t group by f;
thing is, I am just currently myself getting into Doctrine, so I cannot give you a real answer. but you could as shown above, simulate a distinct with group by and transform that into Doctrine. if you want add further filtering then use HAVING after group by.
Just open your repository file and add this new function, then call it inside your controller:
public function distinctCategories(){
return $this->createQueryBuilder('cc')
->where('cc.contenttype = :type')
->setParameter('type', 'blogarticle')
->groupBy('cc.blogarticle')
->getQuery()
->getResult()
;
}
Then within your controller:
public function index(YourRepository $repo)
{
$distinctCategories = $repo->distinctCategories();
return $this->render('your_twig_file.html.twig', [
'distinctCategories' => $distinctCategories
]);
}
Good luck!