Doctrine get non null ArrayCollection - symfony

I would like to get all Entity only if the parameter is part in this entity or if the entity parameter is empty.
I have this:
$qb = $this->createQueryBuilder('cc')
->join('Toblor\Entity\Paramount', 'p')
->select('p')
->Where(':company MEMBER OF p.company_activated')
->setParameter('company ', $company)
return $qb->getQuery()->getResult();
And it is doing to job great. But now I would like to have the same result if company is a part of company_actived OR if company_activated is empty. I have tried an
->Where('(:company MEMBER OF p.company_activated OR p.company_activated IS NULL)')
It trigger me this error
Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.
Is there an easy way to do this thing ? Because I need to implement on a lot of fields.
Thanks you

Is your relation with company_activated ManyToMany or OneToMany.
If it's the case, you need to add:
->leftJoin('p.company_activated', 'ca')
then check if ca IS NULL

Related

Symfony Many-to-many query

I have a question about Symfony's Many-to-many relationships. I have a query, that tries to get all the fields of an entity (outside this part), and on top of that query, it adds the following:
$queryBuilder
->leftJoin('AppBundle:Location', 'location',
Join::WITH, 'location.id IN (entity.locations)')
->andWhere('location.institute=:institute')
->setParameter('institute', $user->getInstitute());
On that entity, a Many-to-many relationship is present: entity has a m2m relationship with location. Now I try to get all entities that have the same institute as the user has.
So I query the locations, and check if the institute of the locations have the same institute.
However, I then get
[Syntax Error] line 0, col 118: Error: Expected Literal, got 'entity'
What should I be doing different? I understand it goes wrong with the IN part of the query.
I think your entity.locations is a variable.
If so, you need to add : in front of and setParameter as well.
Change your code to:
$queryBuilder
->leftJoin('AppBundle:Location', 'location', Join::WITH, 'location.id IN (:locations)')
->setParameter('locations', entity.locations);
->andWhere('location.institute=:institute')
->setParameter('institute', $user->getInstitute());
Please let me know if this solve your issue, thanks!
In the end, I found out that the answer is as follows:
$queryBuilder
->leftJoin('AppBundle:Location', 'location',
Join::WITH, 'location MEMBER OF entity.locations')
->andWhere('location.institute=:institute')
->setParameter('institute', $user->getInstitute());

Set parameter as int array for where in statement in dbal query builder throws array to string conversion exception

I try to bind parameter : [1, 2] in dbal querybuilder in WHERE IN statement
I tried to change $qb->expr()->in() to string version but nothing changed
QueryBuilder creation
$qb = $this->_em->getConnection()->createQueryBuilder()
->select('c.id AS id')
->from('category', 'c')
->andWhere($qb->expr()->in('c.id', ':categories'))->setParameter('categories', [1, 2], \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
Execution:
$qb->execute()->fetchAll();
Error : Array to string conversion
Expects to bind array of integers to querybuilder statement
always love to quote documentation.
// Example - $qb->expr()->in('u.id', array(1, 2, 3))
// Make sure that you do NOT use something similar to $qb->expr()->in('value', array('stringvalue')) as this will cause Doctrine to throw an Exception.
// Instead, use $qb->expr()->in('value', array('?1')) and bind your parameter to ?1 (see section above)
public function in($x, $y); // Returns Expr\Func instance
source: doctrine querybuilder docs
so essentially, unless the categories are numbers, you have to fill an array with placeholders and set those, or if they are numbers, you probably can just use the example.
I assume you have an entity which has a ManyToMany or ManyToOne with a Category entity,
You could just pass an array of Categories and it should work if the array is properly made like so :
qb = $this->_em->getConnection()->createQueryBuilder()
->select('c.id AS id')
->from('category', 'c')
->andWhere($qb->expr()->in('c.id',':categories'))->setParameter('categories', $categoriesArray);
Otherwise, you can try to use setParameter with your array of id by imploding the array :
qb = $this->_em->getConnection()->createQueryBuilder()
->select('c.id AS id')
->from('category', 'c')
->andWhere($qb->expr()->in('c.id', ':categories'))->setParameter('categories', implode(",",[1, 2]));

How to build this query on Symfony with QueryBuilder?

Please I am a beginner on symfony and I have 2 entities: category and professionnal with ORM many to many. And 'City' is an entity with ORM oneToMany with 'professionnal'.
In professionnel I have a property city. I want to show professionnal grouped by categories who have a special cityId putted on parameter in the url.
I put this query on sql
(for example city_id= 10873)
, it gives me the results.
SELECT * FROM sub_category AS a LEFT JOIN professionnel ON professionnel.city_id = 10873
but I don't know how to write with querybuilder.
I put this solution but I have errors:
$city = $paramFetcher->get('city');
$queryBuilder = $em->getRepository(SubCategory::class)
->createQueryBuilder('a')
->leftJoin('App\Entity\Professionnel','p')
->where('p.city = :city')
->setParameter('city', $city);
return $queryBuilder->getQuery()->getResult();
in log:
request.CRITICAL: Uncaught PHP Exception Doctrine\DBAL\Exception\SyntaxErrorException: "An exception occurred while executing 'SELECT c0_.id AS id_0, c0_.name AS name_1 FROM category c0_ LEFT JOIN professionnel p1_ WHERE p1_.city_id = ?' with params ["10873"]: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE p1_.city_id = '10873'' at line 1"
I search on forums too and I found that I can replaced the 'ON' of leftJoin as following, but shows me all professionnals:
$city = $paramFetcher->get('city');
$queryBuilder = $em->getRepository(SubCategory::class)
->createQueryBuilder('a')
->leftJoin('App\Entity\Professionnel','p','WITH','p.city = :city')
->setParameter('city', $city);
return $queryBuilder->getQuery()->getResult();
For the mapping, I put it like this:
class Category
{
/**
* Many professionnels have Many categories.
* #ORM\ManyToMany(targetEntity="App\Entity\Professionnel", mappedBy="Categories")
* #ORM\JoinTable(name="professionnel_category")
*/
private $professionnels;
}
class Professionnel extends User
{
/**
* Many professionel have Many categories.
* #ORM\ManyToMany(targetEntity="App\Entity\Category", inversedBy="professionnels")
* #Groups({"Default", "professionnel", "user"})
*/
private $categories;
}
Thank you so much for your help.
So, assuming that you have your entity relation set up correctly (please update your question with those), I see one mistake above.
If you look at the official Doctrine Query Builder documentation, the leftJoin method's third argument is either WITH or ON constant and not join predicate. That one comes as a 4th argument. But, even then, that join predicate is only used is a very specific use-case, where you want to further define your join relation. By looking at your example, I doubt that is your case.
With that being said, I think your code should look like this:
$city = $paramFetcher->get('city');
$queryBuilder = $em->getRepository(Category::class)
->createQueryBuilder('a');
->leftJoin('App\Entity\Professionnel','p')
->where('p.city_id = :city')
->setParameter('city', $city);
return $queryBuilder->getQuery()->getResult();
Now the question: is that really just a city_id (plain integer) or is that relation to some entity named City?
Please update your question with those details and I will update the answer, if necessary...
Hope this helps...
Firstly, you need describe relations in entities. Read more about this here
Secondary, you must call in join field (read as property), not a Entity.
inside CategoryRepository:
/** #return ArrayCollection|Category[] */
public function getByCityId(int $cityId): ArrayCollection
{
$qb = $this->createQueryBuilder('category');
$qb->leftJoin('category.professional', 'professional')
->leftJoin('category.city', 'city')
->where($qb->expr()->eq('city.id', $cityId));
return $qb->getQuery()->getResult();
}
Inside SomeController:someAction()
$cityId = $paramFetcher->get('city');
$categoriesList = $this->get('doctrine.orm.entity_manager')
->getRepository(Category::class)
->getByCityId($cityId);
As result you'll be have list of category, with joined professional and city.
I suggest to read this article on symfony docs

Doctrine2 - proxy object among regular objects in getResult

In my Symfony2 controller, I have two queries:
like in this example:
$object = $this->getDoctrine()->getManager()
->createQuery('SELECT PARTIAL o.{id,name,field1}
FROM SomeBundle:SomeEntity o
WHERE o.id = :objectId')
->setParameter('objectId', $objectId)
->getResult();
$objects = $this->getDoctrine()->getManager()
->createQuery('SELECT PARTIAL o.{id,name,field1, field2}
FROM SomeBundle:SomeEntity o ')
->getResult();
Effect that I receive in collection $objects is collection of SomeBundle:SomeEntity objects except for the one that I received to variable $object for which I receive Proxy object.
If I output $objects collection and for each element I want to print output that includes fields: name, field1, field2, I receive null for field2 for this object. In fact if I get this $object in any other controller launched with this one together, the field2 is also null on each reference to the object.
For example, if I want to display each object as:
name field1 field2
I get following array for $objects:
nameExample field1Example field2Example
nameExample field1Example field2Example
nameExample field1Example
nameExample field1Example field2Example
nameExample field1Example field2Example
where the third row is the $object.
If I get field2 in the first query it is also visible on getResult of the second one. But that makes me control all fields received for any Entity object in whole Request.
What could I made wrong?
How can I avoid that effect? I still want to work with objects not with multidimensional arrays (as for HYDRATE_ARRAY)
Is there a way to force doctrine to result always with entity objects not with proxies objects?
Thank you in advance.
This happens because Doctrine keeps an internal reference to each entity it returns. When you request an entity you've requested before, it will re-use the previous object. The reason for this is that having two different copies of the same entity would create conflicts if you try to manipulate both of them. For more details, see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/unitofwork.html#how-doctrine-keeps-track-of-objects
The one solution is to detach the entity you got first (using either $em->detach($object) or $em->clear()) before executing the second query. Be aware, any changes you've made that have not been flushed yet will be gone.
Another option is to either refresh the entity using $em->refresh($object) (this will cause it to be fully loaded) or tell Doctrine it needs to refresh all entities for the second query:
$query = $this->getDoctrine()->getManager()->createQuery('SELECT PARTIAL o.{id,name,field1, field2} FROM SomeBundle:SomeEntity o ');
$query->setHint(Query::HINT_REFRESH, true);
$objects = $query->getResult();
This will make Doctrine refresh all the entities it finds for this second query.

Symfony : Custom repository function returns a non-object result

Here is the content of my custom repository function for my entity Feed.
return $this->createQueryBuilder('f')
->select('f, COUNT(s)')
->leftJoin('f.subscriptions','s')
->groupBy('f')
->having('f.inCatalog = TRUE')
->orHaving('COUNT(s) > 0');
->getQuery()->getResult();
I want to get every feed with at least one subscription in my catalog, then browse it in a foreach loop but it returns this :
FatalErrorException: Error: Call to a member function getId() on a non-object in * line *
Any idea how to solve this problem ?
I saw you could do, for example, $feed[0]->getId() but I want an object, not an array.
Some topics are similar but I didn't find any good answer.
EDIT : Well, i think i found the answer to my own question...
To get what i want, i need to remove the COUNT() in the select. I don't want it and it is only needed in the HAVING.
This looks to be working :
return $this->createQueryBuilder('f')
->leftJoin('f.subscriptions','s')
->groupBy('f')
->having('f.inCatalog = TRUE')
->orHaving('COUNT(s) > 0');
->getQuery()->getResult();
Now the result returns an array of objects as i wanted.
Thanks to the people who answered.
You have to use at least a primary key in your select, f.id in this case I guess and group by this id
Try it with partial...
$qb->select('partial f.{id, subscriptions}, count(s.id)');
the results might be given back in an array, so you can try access it
{{ feed[0][0]->getId() }}
see my similar question:
How can I select count(field) and still get an object with createQueryBuilder

Resources