doctrine does not hydration when select custom fields - doctrine-orm

i have tried select fields with doctrine query buidler.
$queryBuilder = $entityManager->createQueryBuilder();
$queryBuilder->select('au.id, au.firstName')
->from('Api\V1\Entity\AgencyUser', 'au')
->orderBy('au.firstName', 'asc');
$queryBuilder->andWhere('au.agency = :agencyId')
->setParameter('agencyId', $agency->getId());
print_r($queryBuilder->getQuery()->getResult(Query::HYDRATE_OBJECT));exit;
result :
Array
(
[0] => Array
(
[id] => 1
[firstName] => agency
)
)
why this is an array ? i want to hydrated result. any idea ?

You want to use Doctrine's Partial Object Syntax
$queryBuilder->select('partial au.{id, firstName}')
As to why it's not returning an object, this is from the same documentation linked above:
By default when you run a DQL query in Doctrine and select only a subset of the fields for a given entity, you do not receive objects back. Instead, you receive only arrays as a flat rectangular result set, similar to how you would if you were just using SQL directly and joining some data.

Related

How to apply equality criteria in doctrine findBy condition?

Is it possible to apply criteria >= condition in Doctrine findBy. I have a query like this:
select * from source where id >= 10
I am looking to apply in following way which will return with reference to Object source.
$this->entityManager->getRepository(Source::class)->findBy(['id' ])
I can use createQueryBuilder but it returns me array result. I need result in same format as above:
$qb = $this->createQueryBuilder('s')
->andWhere('s.id >= :id')
->setParameter('id', 10);
Expected Result:
0 => App\Entity\Source {#845
-id: 10
Can anybody help me?
Thanks in advance.
You could use the repository's matching method.
$criteria = Criteria::create()
->andWhere(Criteria::expr()->gte('id', 10));
$repository->matching($criteria);
Be aware that doctrine can not always hydrate your database data on Entities, when using custom queries. The result is that it only returns array data.

Doctrine 2 specific fields selected via querybuilder is not accessible using getter method

When I use doctrine 2 query builder as below to create a resultset:
$queryBuilder = $this->orm->createQueryBuilder();
$queryBuilder->select("s.id","partial s.{id, name, user}","s.name","concat(u.firstname,' ',u.lastname) fullName")
->add('from', 'Application\Entity\Schools s')
->leftJoin('s.user', 'u', 'WITH', 'u.id = s.user')
->getQuery()->getResult(Query::HYDRATE_ARRAY);
echo "<pre>";
print_r($dd);
die;
It gives following data:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[name] => DAV Public School
)
[id] => 1
[name] => DAV Public School
[fullName] => Manu Sharma
)
[1] => Array
(
[0] => Array
(
[id] => 2
[name] => Delhi Public School
)
[id] => 2
[name] => Delhi Public School
[fullName] => Vipul Sharma
)
)
So when I try to fetch its value using getter method:
$result->getName() doesn't work but I have to use $result[0]->getName().
and error says:
Fatal error: Call to a member function getName() on a non-object
How to choose specific fields inside queryBuilder's select method so that main array values must be accessed using getter methods. Why its not working. Is there anything wrong with my select query.
What is the benefit if specific selected fields can't be accessed using getter method. I believe I'm doing something wrong but it doesn't strike my mind.
Note: While using $result, I removed array_hydrate, that is I'm passing object and hence expecting getter methods to work properly.
The problem you're having is caused by adding additional fields to the SELECT clause. That's causing the result to put the object at index 0 to be able to add additional fields like fullName that you don't have in the entity to the result set.
As far as I understand, all you want is to have a method to get the full name of each user. Instead of solving that problem at the query level, you better just add a method to the User entity:
public function getFullName() {
return sprintf('%s %s', $this->getFirstName(), $this->getLastName());
}
And then just select users the usual way:
SELECT u FROM User u
You can now get the full name of the first user the following way:
$result[0]->getFullName();
You don't need partial objects here. Partial objects have completely different use cases.

How to order by a computed value in DQL

I'm trying to order the results of my query by whether or not they match my original entity on a property. I could do this easily in mySQL with the following query:
SELECT * FROM table
ORDER BY prop = 'value' DESC;
However, in Doctrine, when I attempt the following:
// $qb is an instance of query builder
$qb->select('e')
->from('Entity', 'e')
->orderBy('e.prop = :value', 'DESC')
->setParameter('value', 'value');
// grab values
I get a Doctrine syntax error, 'end of string'. I looked into creating a custom function, but that seems like overkill. I'm fairly new to Doctrine, is there a better way to do this?
Since Doctrine ORM 2.2, you can use the HIDDEN keyword and select additional fields, in this case with a CASE expression:
SELECT
e,
CASE WHEN e.prop = :value THEN 1 ELSE 0 END AS HIDDEN sortCondition
FROM
Entity e
ORDER BY
sortCondition DESC
As I struggeled a while to figure out how to create that query using php syntax here's what I came up with:
$value = 'my-value';
$qb->select('e')
->from('Entity', 'e')
->addSelect('CASE WHEN e.prop = :value THEN 1 ELSE 0 END AS HIDDEN sortCondition')
->setParameter('value', $value)
->addOrderBy('sortCondition', 'DESC');

subquery in join with doctrine dql

I want to use DQL to create a query which looks like this in SQL:
select
e.*
from
e
inner join (
select
uuid, max(locale) as locale
from
e
where
locale = 'nl_NL' or
locale = 'nl'
group by
uuid
) as e_ on e.uuid = e_.uuid and e.locale = e_.locale
I tried to use QueryBuilder to generate the query and subquery. I think they do the right thing by them selves but I can't combine them in the join statement. Does anybody now if this is possible with DQL? I can't use native SQL because I want to return real objects and I don't know for which object this query is run (I only know the base class which have the uuid and locale property).
$subQueryBuilder = $this->_em->createQueryBuilder();
$subQueryBuilder
->addSelect('e.uuid, max(e.locale) as locale')
->from($this->_entityName, 'e')
->where($subQueryBuilder->expr()->in('e.locale', $localeCriteria))
->groupBy('e.uuid');
$queryBuilder = $this->_em->createQueryBuilder();
$queryBuilder
->addSelect('e')
->from($this->_entityName, 'e')
->join('('.$subQueryBuilder.') as', 'e_')
->where('e.uuid = e_.uuid')
->andWhere('e.locale = e_.locale');
You cannot put a subquery in the FROM clause of your DQL.
I will assume that your PK is {uuid, locale}, as of discussion with you on IRC. Since you also have two different columns in your query, this can become ugly.
What you can do is putting it into the WHERE clause:
select
e
from
MyEntity e
WHERE
e.uuid IN (
select
e2.uuid
from
MyEntity e2
where
e2.locale IN (:selectedLocales)
group by
e2.uuid
)
AND e.locale IN (
select
max(e3.locale) as locale
from
MyEntity e3
where
e3.locale IN (:selectedLocales)
group by
e3.uuid
)
Please note that I used a comparison against a (non empty) array of locales that you bind to to the :selectedLocales. This is to avoid destroying the query cache if you want to match against additional locales.
I also wouldn't suggest building this with the query builder if there's no real advantage in doing so since it will just make it simpler to break the query cache if you add conditionals dynamically (also, it's 3 query builders involved!)

How to hydrate an Entity to its object when ordering when a specific computed field?

I need to get the diff from some integer, I've a column 'number' with value like 1 and -1, then I want to use SUM() to compute the difference.
My DQL is:
SELECT
SUM(av.number) AS number_diff,
a
FROM
Articles a
LEFT JOIN a.numbers av
GROUP BY
av.article
ORDER BY
number_diff DESC
It's working but I get a result like this :
array
0 =>
array
0 =>
object (Article)
.... properties
'vote_diff' => string '850' (length=3)
I need to get rid of such structure and get it in this format:
array
0 =>
object (Article)
.... properties
How can I do this?
This is not possible, as number_diff is a computed column. It's not part of the entity.
So, each row is an array containing both the entity and the computed column, instead of just the entity.