Symfony Form Query Builder - symfony

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.

Related

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.

Sortable Sonata Type Model in Admin

Did someone tried the tutorial about Sortable Sonata Type Model in Admin.
I've followed it step by step without missing anything (I'm pretty sure) but can't get a good result at the end.
Basically what I'm trying to do is : I have 3 entities, Article, Tag and ArticleTag (eq to User, Expectation and UserHasExpectation in the tutorial)
Everything seems good until the UserHasExpectationAdmin:
protected function configureFormFields(FormMapper $formMapper){
// ...
$formMapper
->add('userHasExpectations', 'sonata_type_model', array(
'label' => 'User\'s expectations',
'query' => $this->modelManager->createQuery('UserBundle\Entity\Expectation'),
'required' => false,
'multiple' => true,
'by_reference' => false,
'sortable' => true,
))
;
$formMapper->get('userHasExpectations')->addModelTransformer(new ExpectationDataTransformer($this->getSubject(), $this->modelManager));}
I think an attribute 'class' => 'UserBundle\Entity\Expectation' should be added to 'userHasExpectations' field else Symfony says that it's an invalid value.
Then the other problem is in the dataTransformer:
It launch me the error:
Attempted to call an undefined method named "create" of class "Main\CoreBundle\Form\DataTransformer\TagDataTransformer"
I think a use statement should be added but I don't know which one. More over, suppose I have the right use statement I don't realize what the writer is aiming to do, if it's creating UserHasExpectation records why don't he add a userHasExpectations->setUser($this->User) ???
Also I want to add after "vardumping" $this->Subject before :
$formMapper->get('userHasExpectations')->addModelTransformer(new ExpectationDataTransformer($this->getSubject(), $this->modelManager));
It seems to have a proper Entity Object with all fields on NULL values...
FINALLY SOLVED IT!
So, the code of the tutorial contains many...mistakes
In spite of trying to create 'userHasExpectation' in the DataTransformer we just return the object userHasExpectation in the reverse DataTransformer then we create our records in the postPersist and postUpdate of our Admin Class that way :
/**
* {#inheritdoc}
*/
public function postUpdate($object)
{
$position = 0;
$uniqId = $this->getUniqId();
$request = $this->getRequest()->get($uniqId);
$qb = $this->modelManager->createQuery('MainCoreBundle:ArticleTag', 'at');
$TagsToRemove = $qb->where('at.article = :article')
->setParameter('article', $object)
->getQuery()
->getResult();
foreach ($TagsToRemove as $Tag) {
$this->modelManager->delete($Tag);
}
foreach($request["article_tags"] as $tag)
{
$Tag = $this->modelManager->find('MainCoreBundle:Tag', $tag);
$article_tags = new ArticleTag;
$article_tags->setTag($Tag);
$article_tags->setArticle($object);
$article_tags->setPosition($position++);
$this->modelManager->create($article_tags);
}
}
/**
* {#inheritdoc}
*/
public function postPersist($object)
{
$position = 0;
$uniqId = $this->getUniqId();
$request = $this->getRequest()->get($uniqId);
foreach($request["article_tags"] as $tag)
{
$Tag = $this->modelManager->find('MainCoreBundle:Tag', $tag);
$article_tags = new ArticleTag;
$article_tags->setTag($Tag);
$article_tags->setArticle($object);
$article_tags->setPosition($position++);
$this->modelManager->create($article_tags);
}
}
Hope this will help Somebody who has the same trouble.
#Sonata-admin-team : I hope you will read this and have time to update the tutorial in question.
Thanks,
Epixilog
For Sonata 3 adding the class attribute 'class'=> 'UserBundle\Entity\Expectation' resolved the problem for me.

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') );

Symfony2 - list of translated values

I'm using symfony2.4 + sonata + gedmo + a2 lix 1.x
I have one entity name "propriete" with his own translation entity (AbstractPersonalTranslation)
I'm able to create a admin form to CRUD the entity with translation tab (OK).
Now I want to display a part (filter on famille for instance) of the translated values of Propriete in an other admin form.
I tried to create a QueryBuilder
->add('firingTypes', 'entity', array(
'class' => 'Sal\RefBundle\Entity\Propriete',
'query_builder' => function(ProprieteRepository $er) {
return $er->queryMyProprieteEn('u');
}))
From repository:
public function queryMyProprieteEn() {
$qb = $this->createQueryBuilder('u')
->andWhere("u.famille=:famille")
->setParameter("famille", "139");
$query = $qb->getQuery();
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
$query->setHint(\Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE, 'en');
return $query->getResult();
}
But of course I have the following error "Expected argument of type Doctrine\ORM\QueryBuilder", "array" given"
How to handle to create a combobox/checkbox of translated values from a main form ?
Please help
Regards

Symfony2 Doctrine Expr 'IS NOT NULL'

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();

Resources