Symfony2 and Doctrine - how to insert an item from joined table - symfony

I have two tables, game and own. In own's entity I have created OneToMany relationship:
/** #ORM\ManyToOne(targetEntity="Game") */
private $game;
And in game Entity field id is also mapped:
* #ORM\OneToMany(targetEntity="Own", mappedBy="game")
Now I have a problem with inserting new data in my database. I tried simply persisting objects:
$gameown = new Own();
$gameown -> setGame('3');
$gameown -> setUpdated(date("Y-m-d H:i:s"));
$em = $this->getDoctrine()->getEntityManager();
$em->persist($gameown);
$em->flush();
But it doesn't work. Symfony is saying that it must be an Game instance, not a string. How to solve this?
When I try this:
$gameown -> setGame($game->getId('3'));
It insert okay, but... null values.

Or
You can do this way as well
$gameObject = $em->getRepository('YourBundle:Game')->findOneBy(array('id' => 3));
Then you can use
$gameown->setGame($gameObject);

Actually, you have to use a game object, and doctrine will do the work for you.
Think with object, not with table.
First, you have to retrieve your objects (from the database for example) :
$em = $this->getDoctrine()->getEntityManager();
$game = $em->getRepository('AppMonBundle:Game')->find(3);
Then, you can set the relation :
$gameown->setGame($game);

Related

Turn deserialized/denormalized entity into doctrine proxy?

I am persisting some entities to a json based db using the symfony serializer.
When retrieving them from the json db they are deserialized again.
Not all fields are serialized before persisting to the json db.
Is it possible to turn deserialized entities into doctrine proxies, so their relationships can be queried?
Example
App\Entity\Employer and App\Entity\Employee (Employee --ManyToOne--> Employer), Employer is not null on Employee.
The relationship is not serialized before persisting Employee to json db.
$documentFromJsonDb = ...;
/** #var App\Entity\Employee */
$employee = $this->normalizer->denormalize($documentFromJsonDb, 'json');
$employee->getEmployer(); // This returns null :( not making a db call
$employee = MagicMethod($employee);
$employee->getEmployer() // This returns an instance of App\Entity\Employer :)
I had a look into the Doctrine\Common\Proxy\ProxyGenerator so far.
Is there a non hacky way to do this without too much overhead?
Thanks for reading!
I think what you want to do is to merge your decoded entity to be able to use Doctrine abilities ?
📖 Take a look on this documentation of Doctrine : https://www.doctrine-project.org/projects/doctrine-orm/en/2.8/reference/working-with-objects.html#merging-entities
It would be something like :
$documentFromJsonDb = ...;
/** #var App\Entity\Employee */
$employee = $this->normalizer->denormalize($documentFromJsonDb, 'json');
$mergedEmployee = $em->merge($employee);
$mergedEmployee->getEmployer(); // Would this work ? :)
Please tell me if it will do the job ? I did not have time to test it 🤔

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;
}

Doctrine DQL Delete from relation table

Using Doctrine 2 and Symfony 2.0.
I have two Doctrine entities (let's suppose EntityA and EntityB).
I have a ManyToMany relation between them. So a EntityA_EntityB table has been created in database.
Using DQL or QueryBuilder, how can I delete from that relation table EntityA_EntityB?
Docrtine offers something like this to perform something similar:
->delete()
->from('EntityA a')
->where('a.id', '?', $id);
But I don't really get how to perform the deletion of row from the relation table.
$em = ...; // instance of `EntityManager`
// fetch both objects if ID is known
$a = $em->getRepository("YourProjectNamespace:EntityA")->find($id_of_A);
$b = $em->getRepository("YourProjectNamespace:EntityB")->find($id_of_B);
// suppose you have `EntityA::getObjectsOfTypeB` which retrieves all of linked objects of type `EntityB`.
// This method return instacne of ArrayCollection
$a->getObjectsOfTypeB()->removeElement($b);
$em->flush();
Something like this?
Basically, you need to remove related object from collection rather than delete relation itself. you want to remove relation directly you can always use pure SQL, but in DQL that is not possible.
Raw DELETE SQL statement via DBAL Connection object
$conn = $this->getDoctrine()->getManager()->getConnection();
$stmt = $conn->prepare("DELETE FROM EntityAEntityB WHERE id_b IN (:ids_of_b)");
$stmt->bindParam('ids_of_b', $to_delete_ids); // BEWARE: this array has to have at least one element
$stmt->executeUpdate();

Doctrine one-to-many situation: how to easily fetch related entities

To simplify, two entities are defined: User and Comment. User can post many comments and every comment has only one user assigned, thus Comment entity has:
/**
* #var \Frontuser
*
* #ORM\ManyToOne(targetEntity="Frontuser")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="ownerUserID", referencedColumnName="id")
* })
*/
private $owneruserid;
However, when in action:
$orm = $this->getDoctrine()->getManager();
$repo = $orm->getRepository('CompDBBundle:Comment');
$repo->findBy(array('owneruserid' => $uid);
Error occured, that there's no such field like owneruserid.
How can I fetch all the user's comments then? The same happens to similar relations in my DB - looks likes you cannot run find() with foreign keys as parameters. I believe a function $user->getComments() should be automatically generated/recognised by Doctrine to allow efficient, quick access to related entities.
The example's simple but, what if there are more entities related to my User in the same way? Do I have to declare repositories for each and try to fetch them by it's owneruserid foreign keys?
Using doctrine, when you define a related entity it's type is the entity class (in this case FrontUser). Therefore firstly your related entity variable name is misleading. It should be e.g.
private $ownerUser;
Then, in order to do a findBy on a related entity field you must supply an entity instance e.g.
$orm = $this->getDoctrine()->getManager();
$userRepo = $orm->getRepository('CompDBBundle:FrontUser');
$user = $userRepo->findById($uid);
$commentRepo = $orm->getRepository('CompDBBundle:Comment');
$userComments = $commentRepo->findByOwnerUser($user);
If you don't have or want to retrieve the user entity you could use a DQL query with the 'uid' as a parameter instead.

Resources