Doctrine queryBuilder: return object not array - php

I have this query created with doctrine querybuilder, the return i get is an array of arrays.
I would like to get a return that is an array of objects, is this possible?
I know that normally Doctrine returns objects of an entity, bit since i have an inner join to get the name from another table it returns arrays.
Thanks in advance.
$qb->select('u', 'h.name')
->from('AppBundle:UserHose', 'u')
->innerJoin('AppBundle:Hose', 'h', 'WITH', 'u.hoseId = h.id')
->where('u.userId = :userId')
->orderBy('u.id', 'DESC')
->setParameter('userId', $userId);
return $qb->getQuery()->getResult();

you can use this:
return $qb->getQuery()->getResult(Query::HYDRATE_ARRAY);
Or this:
return $qb->getQuery()->getArrayResult();

This isn't possible this way. In other words, you are doing it wrong.
You are telling Doctrine to return a collection of collections containing an entity and a string so this is what you get. Doctrine won't make an object out of that since it does not know how to hydrate such result.
[
[entity, string],
[entity, string],
....
]
If you wish to receive a collection of objects only, you would need to create a new entity that has both fields (related entity and a string property), then use a ResultSet mapping to hydrate that.

if you want array of objects you have to set relation betwen Entities, and create a query by the owning side of relation.
example:
Tourney entity , Invite entity
Invite
/**
* #ORM\ManyToOne(targetEntity="Tourney", inversedBy="invites")
*/
protected $tourneys;
Tourney
/**
* #ORM\OneToMany(targetEntity="Invite", mappedBy="tourneys", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=true, onDelete="CASCADE")
*/
protected $invites;
now you have to make query to the owning side of relation (Invite)
and it will be holding all your join object data with Tourneys in field $invites
and it gives you array of objects. based on your query
remeber of setter $invites as setInvites(Tourney $invites) and by inverse side of relation setTourneys(Invite $tourneys)

Just add \Doctrine\ORM\Query::HYDRATE_ARRAY on getResult() like this
$qb->select('u', 'h.name')
->from('AppBundle:UserHose', 'u')
->innerJoin('AppBundle:Hose', 'h', 'WITH', 'u.hoseId = h.id')
->where('u.userId = :userId')
->orderBy('u.id', 'DESC')
->setParameter('userId', $userId);
return $qb->getQuery()->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

Related

Query builder cannot associate with category entity

I have 2 entities, MyItem and MyItemCategory. When I try to create a query with query builder I get the following error:
Error: Class App\Entity\MyItem has no
field or association named myitem_category_id (500 Internal Server Error)
This is the where part of my query builder:
$queryBuilder = $this->getDoctrine()
->getRepository('App\Entity\MyItem')
->createQueryBuilder('m');
// adds where for category_id:
$queryBuilder->where('m.myitem_category_id = :category_id')->setParameter('category_id',$category_id);
Here're first entities:
/**
* #ManyToOne(targetEntity="MyItemCategory")
* #JoinColumn(name="myitem_category_id", referencedColumnName="id")
*/
private $myItemCategory;
...and my category entity:
/**
* #ORM\OneToMany(targetEntity="MyItem", mappedBy="myItemCategory")
*/
private $myItemCategories;
The querybuilder actually doesn't care about database fields, but instead uses the object mapper, so there is no field my_item_category_id on your Entity, but instead a field myItemCategory
So, you can either do:
$querybuilder
->where('m.myItemCategory = :category')
->setParameter('category', $category) // <-- an actual MyItemCategory object
or you can join it in and check for the id:
$querybuilder
->leftJoin('m.myItemCategory', 'mic')
->where('mic.id = :micid')
->setParameter('micid', $category_id)
(I actually don't know if m.myItemCategory.id = :micid might work ........ you could try ;o))

Doctrine join a table with two

Good morning, as seen in the image below, I have some tables linked.
Using Doctrine (in Symfony2) I'm trying to get an array of Objects Issue which itself contains all IssueMessages and IssueStatusChanged objects but can not.
I have no idea how I can do to join two tables (IssueMessage and IssueStatusChanged) to through their identifiers.
The most we've done is get all Issue with an account of the messages that have:
$dql = 'SELECT x, COUNT(im.id) FROM PanelBundle:Issue x LEFT JOIN PanelBundle:IssueMessages im WITH x.id = im.idIssue';
Does anyone could give me a hand?
THANKS!
You want to use assication mapping; this will have Doctrine manage all the joins for you.
Once in place, $issue will always have the other associated models available automatically without you having to worry about joins.
For the example below (assuming you use annotation), to get messages for an issue just get the issue objects and then use $issue->getMessages();.
<?php
/** #Entity */
class issue
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
// ...
/**
* #OneToMany(targetEntity="issueMessages", mappedBy="issue")
*/
private $messages;
// ...
public function __construct()
{
$this->messages = new Doctrine\Common\Collections\ArrayCollection();
}
}
/** #Entity */
class issueMessages
{
// ...
/**
* #ManyToOne(targetEntity="issue", inversedBy="messages")
* #JoinColumn(name="issue_id", referencedColumnName="id")
*/
private $issue;
// ...
}
If you using yml format for schema orm files than
first you need to write schema and mention oneToMany, manyToOne relationship with table fields & generate entity, repository class.
Than you can use join with two or more tables as below example:
Example of repository class file function:
----------------------------------------------------
public function getReportInfo($idUserDetail)
{
$query = $this->createQueryBuilder('UR')
->select("UR.report_period_start_date, UR.report_period_end_date")
->leftJoin('UR.UserReportDetail', 'URD')
->andWhere('UR.id_user_detail = :id')
->setParameter('id', $id)
->orderBy('UR.report_year', 'DESC')
->addOrderBy('UR.report_month', 'DESC')
->setMaxResults(1);
$resultArray = $query->getQuery()->getArrayResult();
return $resultArray;
}
You can call this function from controller action as below:
-------------------------------------------------------------
public function getUserDetailAction($idUserDetail)
{
$em = $this->getDoctrine()->getManager();
$userDetail = $em->getRepository(
'DemoBundle:UserDetail')
->getReportInfo($idUserDetail);
return $userDetail;
}
I hope this would be useful to you.
I think the problem reside in the DQL syntax (+ missing inverse relation?).
By writing this:
SELECT x, COUNT(im.id) FROM PanelBundle:Issue x
LEFT JOIN PanelBundle:IssueMessages im WITH x.id = im.idIssue
you are joining two "random" table based on the condition provided in the WITH clause. This should usually be ok, but it may confuse the Hydrator component.
In your case you should configure the OneToMany side of the relation in Issue entity, then write something like this:
SELECT x, COUNT(im.id) FROM PanelBundle:Issue x
LEFT JOIN x.issueMessages im
Hope it helps!

Symfony2 - Doctrine - Filtering arrayCollection to get only one object

I am new in Doctrine. I have entities and associations works fine.
My issue:
I have three entities User, Comment, Comment_status.
Comment is connected to main table Finding but this doesnt matter in this case.
Association: Comment <---1:n---> Comment_status <---n:1---> User
That should handle relation between users wathing list of comments and setting like/dislike for every of them.
I am using TWIG to show a list of comments on the page and thats enough for all data like "date", "like count" etc but if I want to get a comment_status for specified user (loged in wathing a page) I dont know how to get this.
if I return array to TWIG "comments" , then loop it for every one of them as "comment" i can access using {{ comment.content }} to data but with comment_status I have no idea bacause it is an array and I just want one element of this array which match to logged in user ID.
I suppose I have to make some DQL ask to DB but have no idea how to do this.
I read some about Criteria in Doctrine but still no idea how to use it.
Can anybody give an step by step solution?
parts of my code:
Controller
> $comments = $em->getRepository('MySpecialBundle:Comment')
> ->findBy(array('finding' => $finding));
>
> return array('comments' => $comments );
Comment entity (part which create association)
> /** * #ORM\OneToMany(targetEntity="Comment_status",
> mappedBy="comment", cascade={"persist", "remove"}, orphanRemoval=true)
> */ protected $commentStatuses;
Comment_status entity (part which create association)
> /** * #ORM\ManyToOne(targetEntity="Comment",
> inversedBy="commentStatuses") * #ORM\JoinColumn(name="comment_id",
> referencedColumnName="id", nullable=false) */ protected $comment;
/**
> * #ORM\ManyToOne(targetEntity="My\MainBundle\Entity\User",
> inversedBy="commentStatuses") * #ORM\JoinColumn(name="user_id",
> referencedColumnName="id", nullable=false) */ protected $user;
User entity (part which create association)
/**
* #ORM\OneToMany(targetEntity="My\SpecialBundle\Entity\Comment_status", mappedBy="user", cascade={"persist"})
*/
protected $commentStatuses;
I want to have a way to get (instead an array collection of all "commentStatuses") only one object which contains an user id of user logged in.
Thank you for help.
You can select and hydrate only the entities matching your criteria in a doctrine querybuilder query. This way you get an already filtered collection. E.g. Something like:
$qb = $this->getEntitymanager()->createQueryBuilder();
$user = $qb->select('u, cs, c')
->from('YourBundle:User', 'u')
->join('u.commentStatuses', 'cs')
->join('cs.comment', 'c')
->where($qb->expr()->eq('u', ':user')
->setParameter('user', $yourLoggedInUser)
->getQuery()->getResult();
This will get you your user and comments/statuses only applicable to that user.
Thanks to #Richard I found a way to solve this.
The right answer is here:
$qb = $this->getEntitymanager()->createQueryBuilder();
$user = $qb->select('c, cs')
->from('MyBundle:Comment', 'c')
->leftjoin('c.commentStatuses', 'cs', 'WITH', 'cs.user = :user')
->setParameter('user', $myLoggedInUser)
->getQuery()->getResult();
Leftjoin - gives all records from Comment not only that contains commentStatus
WITH - choose only right commentStatuses
If I would use #Richard version with second join and WHERE it would show only Comments where user and commentStatus exists.
Anyway thans for help

Symfony2 and Doctrine: how to sort entity collection by dependant entity field

In my sf2 project I access entity collection by calling:
$user_payment_info_datas = $user->getUserPaymentInfoDatas();
In the User entity there is:
/**
* #ORM\OneToMany(targetEntity="UserPaymentInfoData", mappedBy="user")
* #ORM\OrderBy({"payment_info" = "ASC", "payment_info_data" = "ASC"})
*/
private $user_payment_info_datas;
So it's 1:n relation and user has many UserPaymentInfoData's. However, there is another entity called PaymentInfoData that contains the actually values for UserPaymentInfoData's. So the relation is
User -> UserPaymentInfoData -> PaymentInfoData.
So in terms of annotations in UserPaymentInfoData it is:
/**
* #ORM\ManyToOne(targetEntity="PaymentInfoData", inversedBy="user_payment_info_datas")
* #ORM\JoinColumn(name="payment_info_id", referencedColumnName="id")
* #ORM\OrderBy({"title"="ASC"})
*/
private $payment_info_data;
I need to sort the collection returned by
$user_payment_info_datas = $user->getUserPaymentInfoDatas();
ascending by a field from PaymentInfoData (let's call it 'title') and NOT UserPaymentInfoData.
Can I do this with Doctrine annotations? Or without writing DQL?
I know I can do it with:
$user_payment_info_datas = $em->getRepository('STMainBundle:UserPaymentInfoData')
->createQueryBuilder('upid')
->innerJoin ('upid.payment_info_data', 'pid')
->where('upid.user = :user')
->addOrderBy('upid.payment_info', 'ASC')
->addOrderBy('pid.title', 'ASC')
->setParameter('user', $user)
->getQuery()
->getResult();
but the question is, whether it's possible to stay with only annotations as I need to fix it in a few places and it would be convenient to just change annotations and not create query builder in two places.

Elegant way to walk backward through OneToOne table entities with Doctrine

I have a very simply structured entity that contains a simple association
Database_Entity_Tenant
id (primary key)
parentId (id of the parent entry)
code (a simple identifier for the tenant, unique)
I defined parentId in my entity accordingly:
/**
* #Column(type="integer")
* #OneToOne(targetEntity="Tenant")
* #JoinColumn(name="parentTenantId", referencedColumnName="id")
* **/
protected $parentId;
This works fine - the generated database schema resembles my choices and its good.
Now i am writing my first method which basically has to return an array of all the tenants that are chained together, in reverse order (i use this for walking backward through a chain of tenants).
In order to do that i came up with the idea to use a while() loop.
$currentTenant = {DATABASE_ENTITY_TENANT}; // In my real code i fetch the entity object of the current tenant
$chain[] = $currentTenant;
$repository = Database::entityManager()->getRepository('Database_Entity_Tenant');
while(!$currentTenant->getParentId()){
$currentTenant = $repository->findOneBy(array(
'id' => $currentTenant->getParentId()
));
$chain[] = $currentTenant;
}
Any tenant that has no parent (such as the base tenant) will have no parent id (or null), so that would end the while loop.
Now all this may work, but it seems really rough to me. I am fairly new to Doctrine so i don't know much about it but i am sure there is some way to do this more elegantly.
QUESTION
Does Doctrine 2 provide me with any set of functions i could use to solve the above problem in a better way?
If not, then is there any other way to do this more elegantly?
If I'm not getting your problem wrong, you just need to find all the entries in your association table ordered by the parentId. In Doctrine2 you can do the following:
$currentTenant = {DATABASE_ENTITY_TENANT}; // assuming a valid entity
$repository = Database::entityManager()
->getRepository('Database_Entity_Tenant')
->createQueryBuilder('t')
->where('t.parentId IS NOT NULL')
->andWhere('t.parentId < :current') /* < or > */
->setParameter('current', $currentTenant->getParentId()->getId())
->orderBy('t.parentId', 'ASC') /* ASC or DESC, no array_reverse */
->getQuery()
->getResult();
/* At this point $repository contains all what you need because of Doctrine,
* but if you want a chain variable: */
$chain = array();
foreach ($repository as $tenant) {
$chain[] = $tenant->getCode(); // your tenant entity if your entity is mapped correctly
}
Hope this helps!

Categories