Updating entity with mappings in Doctrine2 - symfony

I've been doing straight MySQL for a long time and am now trying to do things the ORM way. I have a site where users create designs. The Design table has a field "userId" that maps to User.id. The Design entity has a value, $user, that defines the relationship between entities:
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="userId", referencedColumnName="id")
*/
private $user;
It's nice, I can now load a Design entity and get the user's last name with $design->user->lastname.
Now let's say a user creates a new design. I save the entity like:
$design = new Design();
$design->setTitle($_POST['title']);
$design->setUserId($_POST['userId']);
$em = $this->getDoctrine()->getEntityManager();
$em->persist($design);
$em->flush();
When I do this, it fails with the message that userId, which allows no nulls, is null. I thought I might be passing it incorrectly, but when I remove $user from the Design entity it works fine, so I think it's expecting a user object to be passed as well, like:
$design->user = new User($userId)
I don't really want to add a database call just to grab the whole user, when I already know the ID which is all I need. What's the easiest way to handle this?

Hope I have understand your db design that you a user table and design table . Each user may have many designs. right? Then in your entity of design have a field user and its setter(public setUser()) method and a getter method(public getUser()). During the persistance of design entity ,it always expect a user object for User field (not an id) in ORM. In ORM a foreginkey relationship between User and Design it maps through by an object.
So in your case during persistance of design entity
1. Make the user object from userId.
$em = $this->getDoctrine()->getEntityManager();//make your entity manager
$userobj=$em->getRepository('yourBundle:User')->find($userId);
$design = new Design();
$design->setTitle($_POST['title']);
$design->setUser($userobj);
$em->persist($design);
$em->flush();
One Imoprtant thing Make sure that in your design entity that do not have the field userId instead of user. if you have you need to remove the getter and setter method of userid and also edit your yml file or anotation(if you use annotation)

Related

How Symfony and Doctrine fetches associations and related entities

I cracked my head trying to realize how Symfony and Doctrine fetch associated entities.
Lets imagine: i have several associated entities:
Company (ManyToOne to City)
City (ManyToOne to Region, OneToMany to Company)
Region (ManyToOne to Country, OneToMany to City)
Country (OneToMany to Region)
When i render Company form i create Form Event Listener (on PRE_SET_DATA) that inserts Region and Country selectboxes to this form.
The values in these fields must be set according to associated Region.
I retrieve current Company Region via:
$company = $event->getData();
$city = $company->getCity()
That works good
But when i try this:
$region = $city->getRegion(); // returns NULL
$country = $region->getCountry(); // returns NULL
these methods returns NULL. But in fact all associations exists and Doctrine association mapping is correct. Why?
According to Doctrine documentation: when i call getter for the proxy object (these ovjects are proxies, right?) - Doctrine should fetch insufficient data from database and update the object.
In fact - methods return NULLs.
How can i get any associated entity? (from any association deep level)
I just needed to remove cache dir...
you should try to get it from your controller instead of the Form Class
$em = $this->getDoctrine()->getManager();
$em->initializeObject($obj);//this will initialize the object you need and fetch the real one from the database and not the proxy class Doctrine returns.
It's returning NULL because it has too many levels company->(1)city->(2)region and the doctrine get lost with the proxy class. if this doesn't work, try to make a DLQ query when you have the city.
if you want to understand how a proxy class looks like dump($company); and you will see that it only show the id of city.

Symfony2 and Doctrine - ManyToOne

I am trying to understand Symfony2, but there is something that is not making sense to me. I reversed engineered an existing database to produce my entities, so maybe thats the problem.
I have a table called availability_alert, nothing special, a few fields including an id (which is the primary key). This table has no link to anything else.
I then have a second table called booking_class, once again nothing special, but it does have the field $availabilityAlert which links to the availability_alerts tables id.
In essence, an Availability Alert can have one or many Booking Class.
Now in my booking class entity, I have the link
/**
* #var \AlertBundle\Entity\AvailabilityAlert
*
* #ORM\ManyToOne(targetEntity="AlertBundle\Entity\AvailabilityAlert")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="availability_alert_id", referencedColumnName="id")
* })
*/
private $availabilityAlert;
So this all looks ok. The setter for it though came out like so
public function setAvailabilityAlert(\AlertBundle\Entity\AvailabilityAlert $availabilityAlert = null)
{
$this->availabilityAlert = $availabilityAlert;
return $this;
}
So that appears to take an AvailabilityAlert Object as a parameter, not the AvailabilityAlert id?
So with the above, I am presuming doing something like this in my controller will not work?
$alert = new AvailabilityAlert();
$bookingClass = new BookingClass();
$bookingClass->setAvailabilityAlert($alert->getId());
Could someone give me some advice on whether things are correct here, or if I should be doing something else? Essentially AvailabilityAlert should be a static table, other tables link to this.
Any advice appreciated.
Thanks
Yes this is correct.
In the Doctrine world, you are working with objects, not with integers or strings, when it comes to relationships between Entities.
You can read more about Doctrine 2 relationships here: http://symfony.com/doc/current/book/doctrine.html#entity-relationships-associations
That's correct. You don't use integers, strings. It's because the relationships are given in entity annotations and Doctrine uses them to figure out what is used exactly to reference the one object from the other. This even let you change how objects reference themselves - for example you change the id to a compound primary key in AvailabilityAlert class and your code wouldn't change much except for the annotations.

FOSUserBundle One-To-One mapped Entity not saved

Hi Folks i have a question regarding implementing One-To-One in Entity FosUserBundle.
User Entity Has One To One Mapping With Profile Entity. I have override the basic RegistrationFormType as per shown in the FOSUserBundle's documentation. record is also saved in both table. but mapping entities show me blank data. Please find respected gist file for same.
UserEntity Gist- https://gist.github.com/ajaypatelbardoli/2f0c81cbdf3b0d136785
ProfileEntity Gist - https://gist.github.com/ajaypatelbardoli/fd02025fd338ed90545e
ProfileFormType gist - https://gist.github.com/ajaypatelbardoli/18ef99a3d0bd1198debc
RegistratonFormType Gist - https://gist.github.com/ajaypatelbardoli/09c047425032391c2445
The problem with your implementation is that you do not update the owning side of the bidirectional association. The Doctrine documentation explicitly states:
See how the foreign key is defined on the owning side of the relation, the table Cart.
In your case the owning side is Profile which you can update automatically in setUserId() as folows:
public function setUserId(\XXXX\Bundle\UserBundle\Entity\User $userId = null)
{
$this->userId = $userId;
$userId->setProfile($this);
return $this;
}
You can access the data from both sides of the relation without problems, Doctrine will look up the corresponding entries.

Doctrine2 ORM Ignore relations in Merge

I'm implementing a REST Api with FOSRestBundle and I have encountered a problem with the modification of existing entity (PUT)
I have a class Student with has a ManyToOne relation
/**
* #JMS\MaxDepth(2)
* #ORM\ManyToOne(targetEntity="ClassRoom", inversedBy="students")
* #ORM\JoinColumn(name="classroom_id", referencedColumnName="id")
*/
protected $classRoom;
When performing a PUT action I only receive the value attributes since i do not want to let the user modify the relations via a put request.
This is a received data example.
{
"id": 3,
"name": "pelayo",
"second_name": "ramon",
"last_name": "fernandez",
"birthday": "1983-08-15T00:00:00+0200"
}
Data gets deserialized with JMS serializer wich sets the $classRoom attribute to null since it didn't find it in the received data.
When performing a merge
$student2 = $this->get('doctrine')->getManager()->merge($student);
If the student2 gets persisted the current relation with classRoom gets erased from the database since the merge sets the relation to null.
This behavior can be dodged by retrieving the current classRoom and setting it to the deserialized entity by hand before the merge, but this is ugly.
Is there any way to tell doctrine to ignore an attribute in a merge from the detached one and make it always use the stored value?
Merge is not the only solution.
The JMSSerializerBundle includes an object constructor for Doctrine entities. When you enable this constructor, the deserialized entities are managed entities that can be persisted(with $em->persist($student)). The only attributes modified on the deserialized entity are the ones mentioned in the JSON from the request.
Here is how you can enable it.

Embedded form persistence : get or create

I work with Symfony2 and doctrine. I currently have an entity called Person. This entity is related to some other entities as a One-To-Many relation (as a Many-To-One unidirectional relation). I want each Person entity to be unique (what I have done in my database by using the UniqueConstraint annotation).
To be clear, I will assume that I have two entities called Home and Car which both have a Many-to-One relation to the target entity Person.
Then I am using forms to create or edit my entities Car and Home. In these forms, I display a embedded form to create a Person entity or select one existing. I explain : the first field of my embedded form is the name of the person. As the user type the name of the person, a list of the existing persons is displayed (using JQuery Autocomplete UI) and if the user select one of them the other fields are autocompleted.
The issue is when the user submit the form with an existing person, I caught an Integrity Error (and I know why, because of my Unique Constraint).
One of the first workaround is to add the id field as an hidden input in the embedded form.
But then the user can edit the other fields and corrupt the current entity.
So no.
Another one could be to prevent the persist in the controller if the Person already exist, but as I am using this in many other entities. I will have to duplicate my code, and I do not want to, as the unique constraint is related to the Person entity and not to the Car or Home entity.
So no again.
The workaround that I am working about is to use a PrePersist Listener waiting for a Person entity, but I do not know how to cancel persist (and maybe it is not possible).
I have the following code :
public function prePersist(LifecycleEventArgs $args) {
$entity = $args->getEntity();
if($entity instanceof Personne) {
$em = $args->getEntityManager();
$persons = $em->getRepository('MyBundle:Person')->findBy(array(
// unique fields
));
if(count($persons) > 0) {
// ... ???
}
}
I have tried a $em->detach but it is useless as I am already persisting the entity.
What I want it is just a kind of a "Get Or Create". I explain, there are only two cases :
the Person entity (not persisted) has all the same fields that one existing in the database (excepted the id field), so the Person entity is the one in the database. I have to "replace" it by the one in the database ;
the Person entity (not persisted) is unique in the database, so we create a new one (persist).
Create your own getOrCreate() method and call it inside your listener.
See this post Symfony2 doctrine FindOneOrCreate
Another possibility would be the data transformers. http://symfony.com/doc/current/cookbook/form/data_transformers.html

Resources