How to do a WHERE when the column is an array? - symfony

I have and Entity : Company, which has a column: Type.
Type can either be a string, or an array of strings.
Ex: Type can be "Foo", "Bar", or array("Foo", "Bar").
I can't figure how to get all the Companies where the type contains "Bar".
I tried
$qb = $this->companyRepository()->createQueryBuilder("c");
$companies = $qb
->select("c")
->Where( $qb->expr()->in('c.type', array($qb->expr()->literal('Bar'))))
->getQuery()
->getResult();
Which only fetch the Companies where the type is "Bar", and not the ones where it is array("Foo", "Bar").
I tried $qb->expr()->like(...) instead of $qb->expr()->in(..) with the same results.
How can I get Companies where the type contains "Bar"?
(Assuming type has more than just the 3 values I gave as an example)

As I wrote in the comments you can't query against single array values when using doctrines array column. But as those columns require you not to use commas inside the array values, it is possible to write a query that utilizes this requirement.
Instead of regex (which would require an doctrine extension), you could also write a LIKE query, like so:
$query = 'Bar';
$qb = $this->companyRepository()->createQueryBuilder("c");
$companies = $qb
->where('c.type LIKE :only OR c.type LIKE :first OR c.type LIKE :last OR c.type LIKE :middle')
->setParameter('only', $query)
->setParameter('first', sprintf('%s%%,', $query))
->setParameter('last', sprintf('%%,%s', $query))
->setParameter('middle', sprintf('%%,%s,%%', $query))
->getQuery()
->getResult()
;
dump($companies);

Here is a similar question with an answer for you.
Symfony2 Doctrine querybuilder where IN
However, I would suggest using DQL if it's an option or just using Doctrine with PDO instead of QueryBuilder.

Related

How can I join two tables without association?

I try to combine two arrays in Symfony that do not have an association field. In documents the field "uuid" is actually the "documentId" in data. Here my approach:
$builder = $this->em->createQueryBuilder();
$result = $builder->select('documents')
->from('App:Documents', 'documents')
->leftJoin('data', 'data')
->andWhere('documents.uuid = data.documentId')
->andWhere('data.fields = :id')
->setParameter('id', 2)
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
But I get the error message that documents has no association data.
You are quite close, but lack a few things.
You need to be more precise with your join and specify which entity is targeted (if there is no relation or inheritance).
// If your entity name is called Data
->leftJoin(Data::class, 'data', 'WITH','data.documentId = documents.uuid')
Let's say you are creating your method from the Documents repository (which by the way should be in singular instead of plural).
Your method would look like this:
$result = $this->createQueryBuilder('documents')
->select('documents as document, data as myData')
->leftJoin(Data::class, 'data', \Doctrine\ORM\Query\Expr\Join::WITH,'data.documentId = documents.uuid')
->getQuery()
->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
But I think there may be an issue with your schema if there is no relation between two entities that are clearly related.

Symfony4 / Doctrine, how select 'distinct' objects ? getResult() return an array of string, not an array of object

From Symfony4/Doctrine, I need to select all "distinct" objects with a entity's repository custom method, below a simple example :
An minimal example table of an entity :
A simple $em->getRepository(MyEntity::class)->findAll(); return all data of my table in object structure.
I'm looking for a way to do the same query with a distinct in relation with the column name. With my example, this query must return the objects 1, 3 and 5.
I tried this entity's repository custom method :
public function getDistinct(){
$query = $this->createQueryBuilder('myentity');
$res = $query
->select("myentity.name")
->distinct(true)
->getQuery()
->getResult();
return $res;
}
But the $res var contains an array of string results, not a array of object (I want an array of entity Objects).
How can I do that ?
Try group by myentity.name instead of distinct.
$res = $query
->select("myentity")
->groupBy("myentity.name")
->getQuery()
->getResult();
This should do the job as expected.

Method findBy() from Doctrine with DateTime

I have the following code, but this would not work:
$event= $this->getDoctrine()
->getRepository('AppBundle:Event')
->findBy(
array(
"datestart" => array(new \DateTime())
)
);
I need a list of the events, which are newer then now.
Where is my misstake?
Or isn't that able to get with the default findBy() function of doctrine ?
findBy only search for exactly matches while you need greater then. In this case and also many other cases you can write your own query. You could use DQL or the queryBuilder. If you want to be able to re-use your query on other places then you could place your query in a repository class which is a good practice too. (check the docs). Now here you find a DQL example that you can place into your controller:
$events = $this->getDoctrine()
->getManager()
->createQuery('SELECT e FROM AppBundle:Event e WHERE e.datestart > CURRENT_DATE()')
->getResult();
i changed your variabele to $events (with s) because you are expecting possible more than one event.

doctrine2 order by array with ids

How I can with doctrine2 order by array with ids ?
I have this query:
$qb = $this->createQueryBuilder('u')
->select('u', 'n', 'c')
->leftJoin('u.notifications', 'n')
->leftJoin('u.channel', 'c')
->andWhere('u.id IN (:ids)')
->setParameter('ids', $ids);
I want that the result has the same order that array with ids, is possible do it ?
Thanks
SOLUTION:
Use FIELD mysql extension with https://github.com/beberlei/DoctrineExtensions
:)
Thanks
Simple solution that doesn't require presorting query result:
$idPositions = array_flip($userIds); // Mapping of id to position
usort($users, function($userA, $userB) use ($idPositions) {
return $idPositions[$userA->id] - $idPositions[$userB->id];
});
If you are using MySQL, sorting with the FIELD() function could accomplish this. DQL doesn't have built-in support for this function, so you'll either have to create a user defined function (see this answer), or create a native query.
I have a solution that is probably very inefficient, but it works. Make sure your results are ordered by id.
$users = $entityManager
->getRepository('User')
->findById($userIds, ['id' => 'ASC']);
$userIdsCopy = $userIds;
sort($userIdsCopy);
array_multisort($userIds, $userIdsCopy);
array_multisort($userIdsCopy, $users);
It's hard to explain how this works, but basically you "remember" the operations that happen when you sort the userId-array, then you apply the opposite of that to the query result.
I found the solution, it is possible using FIELD mysql extension with https://github.com/beberlei/DoctrineExtensions
Thanks
Marc
Which id do you want to order by?
You can use...
->orderBy('u.id', 'asc')
// or n.id
// or c.id
Or you can use multiple order by's ("by's" doesn't seem right to me)...
->addOrderBy('u.id', 'asc')
->addOrderBy('u.name', 'desc') // if it exists

Symfony2 Select one column in doctrine

I'm trying to refine the query trying to select fewer possible values ​​..
For example I have an entity "Anagrafic" that contains your name, address, city, etc.,
and a form where I want to change only one of these fields, such as address.
I have created this query:
//AnagraficRepository
public function findAddress($Id)
{
$qb = $this->createQueryBuilder('r')
->select('r.address')
->where('r.id = :id')
->setParameter('id', $Id)
->getQuery();
return $qb->getResult();
}
there is something wrong with this query because I do not return any value, but if I do the query normally:
//Controller
$entity = $em->getRepository('MyBusinessBundle:Anagrafic')->find($id);
Return the right value.
How do I do a query selecting only one column?
Since you are requesting single column of each record you are bound to expect an array. That being said you should replace getResult with getArrayResult() because you can't enforce object hydration:
$data = $qb->getArrayResult();
Now, you have structure:
$data[0]['address']
$data[1]['address']
....
Hope this helps.
As for the discussion about performance in comments I generally agree with you for not wanting all 30 column fetch every time. However, in that case, you should consider writing named queries in order to minimize impact if you database ever gets altered.
You can use partial objects to only hydrate one field and still return a object.
This worked for me:
$qb = $repository->createQueryBuilder('i')
->select('i.name')
->...
Use partial objects like this to select fields
$qb = $this->createQueryBuilder('r')
->select(array('partial r.{id,address}'))
...
Put your field names between the brackets

Resources