How to change Query to contain data from joined table? - symfony

I have simple Entity:
id
username
guard
"guard" is id of another user from the same Entity. I have to render view with simple table:
username | name of guard
-------------------------
John | Bob
I tried to do that by query:
$ur = $this->getDoctrine()->getRepository(User::class)->createQueryBuilder('u')
->leftJoin(User::class, 'u2', \Doctrine\ORM\Query\Expr\Join::WITH, 'u.guard = u2.id')
->getQuery()
->getResult();
but it gives me just id and username, no joined data.
I know that entire query should be like:
SELECT
*
FROM
user u0_
LEFT JOIN user u1_ ON (u0_.guard = u1_.id)
but I can't find the way to implement that by QueryBuilder and then to access that in twig template.
Regards

OK, I found out the mistakes in my code:
I tried to set that OneToOne realtion and that was small mistake, but I needed here ManyToOne.
/**
* Many Users have One Guard (User)
* #ORM\ManyToOne(targetEntity="User")
*/
private $guard = 0;
When I did that Symfony automatically force me to change my code and in column "guard" I have to insert User object.
After that I don't need join anymore - just select data from table and guard column includes User object which I can use in Twig, etc.
namespace AppBundle\Entity;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
public function findAllDB()
{
$qb = $this->createQueryBuilder('u');
$query = $qb->getQuery();
return $query->execute();
}
}

Related

Getting custom getter values from Entity with DQL in symfony2

I'm using FOSUserBundle and FOSRestBunldle with Symfony 2.8 and have to get a short user List with age, however there is no field 'age' in the user database, which is why my User entity class has this custom getter to calculate the age from the birthdate field
public function getAge()
{
$now = new \DateTime('now');
$age = $this->birthdate->diff($now);
return $age->format('%y');
}
Getting my user list with "u.age" and serializing it to json however, does not work, as there is no real field associated with u.age
$query = $em->createQuery('SELECT u.username, u.age FROM AppBundle:User u');
$users = $query->getResult();
Using the Repository with ->findAll() would get the ages, but also loads a lot of other related entities (posts, comments by the user) which are not needed here and would be a bit of an overload.
How can i get a list of my users with just their username and respecive age?
thank you for your help!
I have found the solution. Using the Annotation #VirtualProperty tells the serializer to get the value.
use JMS\Serializer\Annotation\VirtualProperty;
has to be included into Entity class, so annotation works.
/**
* #VirtualProperty
*/
public function getAge()
{
You don't have age field in DB, which also means you don't have it in Doctrine mapping, therefore you can't select it. Doctrine doesn't know anything about it.
You need to select data that is required to calculate it inside entity instance. In this case in order to calculate user's age you probably want to select birthday date.
E.g.:
$query = $em->createQuery('SELECT u.username, u.birthday FROM AppBundle:User u');
$users = $query->getResult();
Then you should be able to get age from your entity in PHP code.

limit columns returned in relationnal entity symfony2

Is it possible to filter an entity and display only few columns in symfony2?
I think I can do a custom query for this, but it seems a bit dirty and I am sure there is a better solution.
For example I have my variable $createdBy below, and it contains few data that shouldnt be displayed in this parent entity such as password etc...
/**
* #var Customer
*
* #ORM\ManyToOne(targetEntity="MyCompany\Bundle\CustomerBundle\Entity\Customer")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="created_by", referencedColumnName="id", nullable=false)
* })
*/
protected $createdBy;
So I need to display my Customer entity, but only containing fields like id and name for example.
EDIT :
I already have an instance of Project, the entity with my createdBy field, and I want to grab my customer data 'formatted' for this entity and not returning too much fields like password ...
Thanks
It sounds like expected behavior to me. The doctrine documentation seems to imply that eager fetching is only one level deep.
According to the docs:
Whenever you query for an entity that has persistent associations and
these associations are mapped as EAGER, they will automatically be
loaded together with the entity being queried and is thus immediately
available to your application.
http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-objects.html#by-eager-loading
The entity being queried has eager on createdBy so it will be populated.
to bypass you can create a method in your entity repository as following :
// join entities and load wanted fields
public function findCustom()
{
return $this->getEntityManager()
->createQuery(
'SELECT p FROM AppBundle:Product p ORDER BY p.name ASC'
)
->getResult();
}
hope this helps you
try this and let me know if it works, you should fill the right repository name
'XXXXBundle:CustomerYYYY', 'c'
public function findUser($user_id){
$qb = $this->_em->createQueryBuilder('c')
->select(array('c', 'cb.id', 'cb.name'))
->from('XXXXBundle:Customer', 'c')
->where('c.id <> :id')
->leftJoin('c.createdBy', 'cb')
->setParameter('id', $user_id)->getQuery();
if ($qb != null)
return $qb->getOneOrNullResult();
return null;
}

Custom SELECT for findBy in Doctrine

I intend to build multilingual website. So I have DB table with columns:
id
text_en
text_pl
When getting data from DB I'd like to have only id and text fields. Normally, I'd issue:
SELECT id, text_$locale AS text FROM page ...
How to do it in Doctrine so that I have such SELECT done automatically when I use findBy() or findOneBy()? Is Query Builder my only option?
Creating a query is the semantic option; you should put it in as a custom method in a repository.
I'm posting an example here so that I can use it for reference later on.
Quick example:
<?php
namespace Acme\AppBundle\Entity;
use Doctrine\ORM\EntityRepository;
/**
* PageRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class PageRepository extends EntityRepository
{
/**
* Gets and id and page name based by ID
* #return array
*/
public function findNameById($id)
{
$query = $this->getEntityManager()
->createQuery("SELECT p.id, p.name
FROM Acme\AppBundle\Entity\Page p
WHERE p.id = :pageId");
$query->setParameter('pageId', $id);
$result = $query->getOneOrNullResult();
return $result;
}
}
Correct, you'll have to use a querybuilder or native query if you want to select specific columns.
Specifying individual columns using findBy is not possible. You could lazy-load associations to entities in other tables but at a minimum findBy will return all columns from the entity's table.

Symfony2: How to create custom query methods on related entities

I have a User entity which has an ArrayCollection of Positions. Each Position has for sure a user_id property.
Now i want to get all positions from a user (to get all i would do $user->getPositions()) that are matching a specific query, for example have a date property that matches the current date. Therefor i want to do something like $user->getCurrentPositions() and it should return a subset of the positions related to that user.
How is that possible?
EDIT:
What i really wanna do is something like this in my controller:
$em = $this->getDoctrine()->getManager();
$users = $em->getRepository('fabianbartschWhereMyNomadsAtBundle:User')->findAll();
foreach ($users as $user) {
$positions = $user->getCurrentPositions();
foreach ($positions as $position) {
echo $position->getLatitude().'<br>';
}
}
I wanna iterate over all users and from each user i want to have the relevant positions. But that isnt possible from the repository i guess, as i get the following message: Attempted to call method "getCurrentPositions" on class ...
If you are using Doctrine you can use the built-in Criteria API which is meant for this purpose exactly.
Collections have a filtering API that allows you to slice parts of data from a collection. If the collection has not been loaded from the database yet, the filtering API can work on the SQL level to make optimized access to large collections.
Ok i found out, its for sure possible with Repositories:
Entity\User.php
/**
* #ORM\Entity(repositoryClass="fabianbartsch\WhereMyNomadsAtBundle\Entity\UserRepository")
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
Entity\UserRepository.php
/**
* UserRepository
*/
class UserRepository extends EntityRepository
{
public function getCurrentPositions()
{
$query = $this->getEntityManager()
->createQuery(
"SELECT p
FROM xxx:Position p
WHERE p.start <= '2014-08-17' AND p.end >= '2014-08-17'"
);
try {
return $query->getResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
}
In the user object only related position entries are affected by the query, so is no need to join user entity with the position entity. Pretty simple, should just try out instead posting on stackoverflow, sry guys :P

Symfony2 Form, lot of querys with a Entity type (Doctrine2)

I have 3 entities: person, with an ID, employee and applicant.
Entity person have vars employee and applicant, and OneToOne relationship.
Employee and Applicant have a person as an ID, with referencedColumnName="id", and a relationship OneToOne.
Fine, When I create a form with the entity person, to display a input select with all applicants, thanks to fuzzy-loading of Doctrine2 make queries to retrieve each person, each related candidate and related empleado, which means that a bd 2000 people are doing almost 6000 requests bd to display only the name.
If I don't print the form, no problem, but, if I put this in the view:
{{ form_rest(formularioEnlazarCandidato.person) }}
And Doctrine2 execute a lot of querys.
I'm not sure how to fix this, as to show an entity in the form will not let me do only select per.id and per.name.
I had similar problem and they helped me - look here Optimize DQL with double join. Basically you need fetch join in your repository - I did:
class ProfileRepository extends EntityRepository {
public function findAll()
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder()
->select("p, stu, sta, pdd, pdt, pdc")
->from('AldenBonBundle:Profile', 'p')
->leftJoin('p.studies', 'stu')
->leftJoin('stu.statute', 'sta')
->leftJoin('p.disabilityDegree', 'pdd')
->leftJoin('p.disabilityType', 'pdt')
->leftJoin('p.disabilityCode', 'pdc')
->orderBy('p.profileId')
;
$res = $qb->getQuery()->getResult();
return $res;
}

Resources