Symfony2 Doctrine Expr 'IS NOT NULL' - symfony

I'm using the FormType for an Entity of mine, and setting up an entity field.
I need two Where clauses in an And, and from what I've read on the Query Builder page, this is at least how I should go about it:
'query_builder' => function ($er){
$qb = $er->createQueryBuilder('p');
$qb
->where($qb->expr()->andx(
$qb->expr()->in('p', '?1'),
$qb->expr()->not(
$qb->expr()->eq('p.location', 'NULL')
)
))
->setParameter(1, $this->totalScope)
;
return $qb;
},
However, the not(eq('col', 'NULL')) doesn't achieve the desired result, and in fact, errors with:
Error: Expected Literal, got 'NULL'

You can use isNotNull:
'query_builder' => function ($er){
$qb = $er->createQueryBuilder('p');
$qb
->where($qb->expr()->andx(
$qb->expr()->in('p', '?1'),
$qb->expr()->isNotNull('p.location')
))
->setParameter(1, $this->totalScope);
return $qb;
},

You can also use DQL in your queryBuilder, which is much less ugly IMO.
Quick and dirty example from a controller:
$repo = $this->getDoctrine()->getRepository('AcmeBundle:Transaction');
$query = $repo->createQueryBuilder('t')
->where('t.timestamp > :timestamp')
->andWhere('t.pinNumber IS NOT NULL')
->setParameter('timestamp', new \DateTime('1 day ago'))
->getQuery()
;
Easier to read in my estimation.

You can use the QueryBuilder to find the results,
$query=$this->dm->createQueryBuilder('AppBundle:DocumentName')
->field('fieldName')->notEqual(null);
$data=$query->getQuery()->execute();

Related

Symfony Form Query Builder

I have a problem with my query builder but I do not know how to fix this error can you help me please?
So here is my problem, I want to retrieve the list of questions that are not in my questionnaire and have the same theme as my questionnaire.
Here is my code:
$builder
->add('orderQuestion')
->add('idQuestion', EntityType::class, [
'class' => Question::class,
'query_builder' => function(EntityRepository $er) use ($idTheme, $idQuestionnaire){
$resultatQuestion = $er->createQueryBuilder('questionn')
->select('questionn.id')
->innerJoin('App\Entity\SurveyQuestion', 'surveyQuestion', 'WITH', 'questionn.id = surveyQuestion.idQuestion')
->where('surveyQuestion.idSurvey = :idSurvey')
;
$resultat = $er->createQueryBuilder('q')
->leftJoin('q.surveyQuestions', 'sQ')
->leftJoin('sQ.idSurvey', 's')
->where('q.idTheme = :idTheme')->setParameter('idTheme', $idTheme)->setParameter(':idSurvey', $idQuestionnaire)
->andWhere($er->createQueryBuilder('question')->expr()->notIn('q.id', $resultatQuestion->getDQL()))
;
return $resultat;
},
'choice_label' => function ($question) {
return $question->getLabel();
},
])
;
But, with this code a have this error : "Warning: get_class() expects parameter 1 to be object, array given".
How can I solve this problem ?
could you modify your code
$resultat = $er->createQueryBuilder('q')
->leftJoin('q.surveyQuestions', 'sQ')
->leftJoin('sQ.idSurvey', 's')
->where('q.idTheme = :val')
->andWhere('q.id NOT IN ' . $test)
->setParameter('val', $idTheme)
->getQuery()
->getResult()
;
So, to be clear, as I mentioned in the comment and in the Symfony's documentation - 'query_builder' can either be a QueryBuilder object, a callable or null.
This way you need to remove ->getQuery() and ->getResult() from your second query.
Update
So, thanks for the clarification from #msg in comments. And according it, you also need to remove from the first statement ->getQuery() and ->getResult() too and just add there ->getDQL()
And it should work.

Doctrine findBy with multiple conditional fields

I have some bad data in the table but not all fields have null values and I want to get all bad rows with one iteration by implementing something like this, if possible.
$contactObj = $this->em->getRepository("ImporterBundle:Contact")
->findBy([$field1 => null OR $field2 => null OR $field3 => null ...]);
Are there is a solution to do something like above example without using repositoryClass?
You can use the matching(Criteria $criteria) function of Doctrine\ORM\EntityRepository:
use Doctrine\Common\Collections\Criteria;
$criteria = Criteria::create()
->where(Criteria::expr()->isNull('functions'))
->orWhere(Criteria::expr()->isNull('salutation'))
->orWhere(Criteria::expr()->isNull('category'))
->orWhere(Criteria::expr()->isNull('address'))
->orWhere(Criteria::expr()->isNull('city'))
->orWhere(Criteria::expr()->isNull('company'));
$contactObj = $this->em->getRepository("ImporterBundle:Contact")
->matching($criteria);
Doctrine expression builder
So I just need to use repository class
And use expressions.
public function getBadData() {
$db = $this->createQueryBuilder('c');
return $db->select('c')
->where($db->expr()->isNull('c.functions'))
->orWhere($db->expr()->isNull('c.salutation'))
->orWhere($db->expr()->isNull('c.category'))
->orWhere($db->expr()->isNull('c.address'))
->orWhere($db->expr()->isNull('c.city'))
->orWhere($db->expr()->isNull('c.company'))
->getQuery()
->getResult();
}
As JimL suggested, I had change repository method by using orX()
public function getBadData() {
$db = $this->createQueryBuilder('c');
return $db->select('c')
->where($db->expr()->orX()->addMultiple(
[
'c.functions is null',
'c.salutation is null',
'c.category is null',
'c.address is null',
'c.city is null',
'c.company is null'
]
))
->getQuery()
->getResult();
}
Which now should be more readable.

Symfony Query Builder: remove results from a request from another requests

I have a first request (I used QueryBuilder but it is a simple findAll()):
public function findAllRosters(){
$qb = $this->createQueryBuilder('r')
;
return $qb->getQuery()
->getResult();
}
I want to remove from the results of this first query all results from another query:
public function findOtherRosters($user){
$qb = $this->createQueryBuilder('r')
->leftJoin('r.members', 'm')
->addSelect('m')
->where('m.user = :user')
->setParameter('user', $user)
;
return $qb->getQuery()
->getResult();
}
Is there a simple way? It seems that using a where NOT IN might be the way forward..
EDIT
I have tried to follow this exemple: https://stackoverflow.com/a/22616937/4228086 see my answer
Have a look at this stackoverflow solution
Here q2 is your second query, the sub result you want to reduce the first result with.
Hope that helps.
After much googling; I finally found the right Query:
public function findOtherRosters($user){
$q2 = $this->createQueryBuilder('r')
->leftJoin('r.members', 'm')
->addSelect('m')
->where('m.user = :user')
->setParameter('user', $user);
$qb = $this->createQueryBuilder('ro');
$qb
->where('ro not IN (:rosters)')
->setParameter('rosters', $q2->getQuery()->getResult())
;
return $qb->getQuery()
->getResult();
}
Hope it can help others with the same issue

Symfony2 simple query: can't fetch an object, only array

The following query in Symfony2.6 works with getArrayResult(); BUT doesn't work with getResult(); or getOneOrNullResult();. This means that I can't fetch an object but only an array.
If I use this query, all I get is a white/blank page (not even the symfony debug toolbar). Note that in my twig template I just do a {{ dump() }} of the query result.
The table structure is easy (it's a list of books read by the users):
id, user, book, status, vote, review
(user, book and status are foreign keys)
public function selectOneRecordBy2Ids($user_id, $book_id)
{
/* #var $qb QueryBuilder */
$qb = $this->createQueryBuilder('l');
$qb->select('l');
$qb = $qb->Where($qb->expr()->eq('l.user', ':first'));
$qb = $qb->andWhere($qb->expr()->eq('l.book', ':second'));
$qb = $qb->setParameters(array('first' => $user_id, 'second' => $book_id));
return $qb->getQuery()->getOneOrNullResult();
}
I've noticed a few bad practices here, so let me correct them:
public function selectOneRecordBy2Ids(User $user, Book $book)
{
/* #var $qb QueryBuilder */
$qb = $this->createQueryBuilder('l');
$qb
->andWhere($qb->expr()->eq('l.user', ':first'))
->andWhere($qb->expr()->eq('l.book', ':second'))
->setParameters(array('first' => $user, 'second' => $book));
return $qb->getQuery()->getResult();
}
Select is not necessary if you work only with one entity and you don't fetch any relations. QB returns $this so you can chain the method calls.
Try to use entities as parameters instead of primitive types (if it is possible). If not, then you have to use primitive types as primitives in QB. In this case you'll need a few joins:
->select('l')
->join('l.user', 'u')
->join('l.book', 'b')
->andWhere($qb->expr()->eq('u.id', ':first'))
->andWhere($qb->expr()->eq('b.id', ':second'))
->setParameters(array('first' => $user_id, 'second' => $book_id));
If you want to fetch only one record, then you may have to limit the results by setting the max results:
->setMaxResults(1)
I hope this helps and solves your original problem as well.
getOneOrNullResult() does not return the record, but tells you if any record in database is found, or not.
You might want to use getSingleResult()

Doctrine / Symfony: convert custom type to database value before using QueryBuilder

I have defined a custom Doctrine data type for Uuid. When I search for an object using find($uuid), it works correctly, i.e. the attribute is converted using convertToDatabaseValue() before executing the query, and converted back with convertToPhpValue() when value is retrieved.
The conversion doesn't work if I use the QueryBuilder. Example:
$qb = $this->createQueryBuilder('s');
$qb = $qb->where( //some conditions...
$qb->expr()->eq( 's.uuid', ':uuid' ))->setParameter( 'uuid', $uuid );
I found two similar unanswered questions:
Symfony Doctrine datatype only works in findBy not querybuilder
Doctrine 2 Custom Types
It looks like that the conversion is in fact ignored.
How can I force the conversion of the parameter before executing the query? Is there a way to access the convertToDatabaseValue() function of the custom data type from the repository?
Thanks
Yes setParameter() has third parameter, but the type of third param as string is worked for me not the object.
You can do it in following way.
$qb = $this->createQueryBuilder('s');
$qb = $qb->where( //some conditions...
$qb->expr()->eq( 's.uuid', ':uuid' ))->setParameter( 'uuid', $uuid, 'uuid' );
If you dont know what exactly key is for datatype 'uuid' is.
Then use print_r(Type::getTypesMap()); to get list of all dataypes added.
In my case it was
Array
(
[array] => Doctrine\DBAL\Types\ArrayType
[simple_array] => Doctrine\DBAL\Types\SimpleArrayType
[json_array] => Doctrine\DBAL\Types\JsonArrayType
[object] => Doctrine\DBAL\Types\ObjectType
[boolean] => Doctrine\DBAL\Types\BooleanType
[integer] => Doctrine\DBAL\Types\IntegerType
[smallint] => Doctrine\DBAL\Types\SmallIntType
[bigint] => Doctrine\DBAL\Types\BigIntType
[string] => Doctrine\DBAL\Types\StringType
[text] => Doctrine\DBAL\Types\TextType
[datetime] => Doctrine\DBAL\Types\DateTimeType
[datetimetz] => Doctrine\DBAL\Types\DateTimeTzType
[date] => Doctrine\DBAL\Types\DateType
[time] => Doctrine\DBAL\Types\TimeType
[decimal] => Doctrine\DBAL\Types\DecimalType
[float] => Doctrine\DBAL\Types\FloatType
[binary] => Doctrine\DBAL\Types\BinaryType
[blob] => Doctrine\DBAL\Types\BlobType
[guid] => Doctrine\DBAL\Types\GuidType
[geometry] => CrEOF\Spatial\DBAL\Types\GeometryType
[point] => CrEOF\Spatial\DBAL\Types\Geometry\PointType
[polygon] => CrEOF\Spatial\DBAL\Types\Geometry\PolygonType
[linestring] => CrEOF\Spatial\DBAL\Types\Geometry\LineStringType
)
And my doctrine code was something like this.
$queryBuilder = $this->createQueryBuilder('c');
$queryBuilder
->where('st_contains(:polygon, point(c.latitude, c.longitude) ) = 1')
->setParameter('polygon', $city->getPolygon(), 'polygon');
Here's the solution: the function setParameter() has a third argument $type which is used to declare the typology of the parameter. The custom declared type can be retrieved with the getType() function of the Doctrine Type class:
$qb = $this->createQueryBuilder('s');
$qb = $qb->where( //some conditions...
$qb->expr()->eq( 's.uuid', ':uuid' ))->setParameter( 'uuid', $uuid, Type::getType('uuid') );

Resources