Doctrine: Update whole Entity - php

first off some code:
class User {
* #ORM\OneToMany(targetEntity="Profile", mappedBy="user")
*/
protected $profiles;
}
(There's come more code, but this is the part affecting my problem).
So for example I have
Already in Database
User1: id = 1
Profile1: id = 1, parent = User1
Profile2: id = 2, parent = User2
Not yet persisted
Profile3:
Profile4:
What I want to do is to be able to just call:
$user1->removeAllProfiles(); $user1->addAllNewProfiles(array($profile3, $profile4));
and this should automatically delete all the old profiles and add all the new.
I hope it's clear what I want to achieve. Anyone having an idea?

You can update your property annotation to make use of orphanRemoval...
/** #OneToMany(targetEntity="Profile", mappedBy="user", orphanRemoval=true) */
protected $profiles;
This tells Doctrine to remove any profiles that are left without an associated User object, so when you call $user->removeAllProfiles(); and then call $em->flush() any previous Profile objects associated with the user will be removed from the database.

Related

How do I set up a Rails "has_one :through" association with Doctrine?

I come from a Rails background and am not really familiar with Doctrine. I am trying to set up a similar association to this one in Rails.
I have a UserRelation entity that contains a combination of user_id and company_id with a primary key. The same user can belong to multiple companies, and most data is stored with user_relation_id.
So, in this example I have a Template that has the following association set up which works fine:
/**
* The UserRelation entity who created the template.
*
* #ORM\ManyToOne(targetEntity="UserRelation")
* #ORM\JoinColumn(name="user_relation_id", referencedColumnName="id", nullable=false)
*/
protected $creator;
In this example I know I can just add a method to my template entity along the lines of:
public function getUser(): User
{
return $this->creator->getUser();
}
but I need it to be filterable so that I can get all Template entities by user_id or company_id in a repository or controller like this:
$company = $entityManager->getRepository('Company')->find($company_id);
$templatesForCompany = $entityManager->getRepository('Template')->findBy('company' => $company);
Is there any way to set up this relationship so I can query it like above, instead of having to resort to raw SQL?

Symfony3.4 - collection reference same entity field lose linked association

Sorry about the title, it's quite hard to describe it with just a few words. Here's the problem:
I have a customer entity which has a OneToMany with Website and customerTrackingIds :
class Customer {
...
/**
* #var ArrayCollection
* #Serializer\Exclude()
* #ORM\OneToMany(targetEntity="AppBundle\Entity\WebSite", mappedBy="customer",cascade={"persist","remove"},orphanRemoval=true)
*/
private $webSites;
/**
* #var ArrayCollection
* #Serializer\Exclude()
* #ORM\OneToMany(targetEntity="AppBundle\Entity\CustomerTrackingId", mappedBy="customer",cascade={"persist","remove"})
*/
private $customerTrackingIds;
...
}
And Website:
class WebSite {
/**
* #var Customer
* #Serializer\MaxDepth(1)
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Customer", inversedBy="webSites")
* #ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $customer;
/**
* #var ArrayCollection
* #Serializer\Exclude()
* #ORM\OneToMany(targetEntity="AppBundle\Entity\CustomerTrackingId", mappedBy="website")
*/
private $customerTrackingIds;
}
Customer has multiple website and multiple trackingIds. Each tracking ID is associated with one of the customer's website, but more trackingIds can exist for the same Website.
I use https://github.com/ninsuo/symfony-collection to handle the collection of website/trackingIds in the same page but when i go edit the information something really weird (at least for me) happens.
Looking in my debugger session i saw that when the form loads data from submit in my controller:
$formCustomer = $this->createForm( CustomerFormType::class, $customer );
$formCustomer->handleRequest( $request );
if ( $formCustomer->isSubmitted() && $formCustomer->isValid() ) {
$em = $this->getDoctrine()->getManager();
$em->persist( $customer );
$em->flush();
When the request is handled all of the elements of TrackingIds has their website correctly set, but inside the website the customer link gets lost (becomes null).
What happens next is that when all the data get persisted i lost in my database the phisical association between website <-> customer (customer becomes null)
How can i fix this?
If you will ever land here i solved the issue simply double-checking my website collection form type.
Since using https://github.com/ninsuo/symfony-collection i created a new FormTheme to render the collection add/delete stuff in my page with just one field for the website collection which was the website name.
Anyways, inside my website collection formType i had TWO fields, name AND, guess what, CUSTOMER.
Since the FormTheme was rendering just the name field, the other one becomes null automatically, so when it was handled by the controller he was actually doing that right.

ManyToOne relationship + How to use in both directions

I have 2 tables like this:
Users
- UserID
- Username
- Password
- ...
Players
- playerID
- playerName
- ...
- User
The relation is ManyToOne (see the picture) and it's not required.
I've generated my entities automatically with Doctrine. In my player Entity I have:
/**
* #var \NV\VolleyScoutBundle\Entity\Users
*
* #ORM\ManyToOne(targetEntity="NV\VolleyScoutBundle\Entity\Users")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user_id", referencedColumnName="user_id")
* })
*/
protected $user;
But I don't have a $player variable in my Users Entity. In what way can I add this? Tried to do this but gave me different errors. What I'm trying to do is add a player form to my register form.
So in my RegisterType (=form) I woud like to add ->add('player', new PlayerType()). But that's not possible without a $player variable in my Users entity.
What type of relation do I need to setting for $player in my Users entity?
You have to add annotation in user entity.
In Player Enity
#ORM\OneToMany(targetEntity="Players", mappedBy="user")
protected $player;
In User Entity:
#ORM\ManyToOne(targetEntity="Users", inversedBy="player")
#ORM\JoinColumn(name="user_id", referendecColumn="UserId")
proteced $user;
This is only a draft. You have to write full namespaces for target entities, and correct errors if there are some.
A lot of setails you can find here: Doctrine documentation - working with association
Try to use small caps for table names, because MySQL under linux doesn't like uppercaps.
$player must be instance of ArrayCollection

Doctrine 2 - How to use objects retrieved from cache in relationships

I'm working in a project that use Doctrine 2 in Symfony 2 and I use MEMCACHE to store doctrine's results.
I have a problem with objects that are retrieved from MEMCACHE.
I found this post similar, but this approach not resolves my problem: Doctrine detaching, caching, and merging
This is the scenario
/**
* This is in entity ContestRegistry
* #var contest
*
* #ORM\ManyToOne(targetEntity="Contest", inversedBy="usersRegistered")
* #ORM\JoinColumn(name="contest_id", referencedColumnName="id", onDelete="CASCADE"))
*
*/
protected $contest;
and in other entity
/**
* #var usersRegistered
*
* #ORM\OneToMany(targetEntity="ContestRegistry", mappedBy="contest")
*
*/
protected $usersRegistered;
Now imagine that Contest is in cache and I want to save a ContestRegistry entry.
So I retrieve the object contest in cache as follows:
$contest = $cacheDriver->fetch($key);
$contest = $this->getEntityManager()->merge($contest);
return $contest;
And as last operation I do:
$contestRegistry = new ContestRegistry();
$contestRegistry->setContest($contest);
$this->entityManager->persist($contestRegistry);
$this->entityManager->flush();
My problem is that doctrine saves the new entity correctly, but also it makes an update on the entity Contest and it updates the column updated. The real problem is that it makes an update query for every entry, I just want to add a reference to the entity.
How I can make it possible?
Any help would be appreciated.
Why
When an entity is merged back into the EntityManager, it will be marked as dirty. This means that when a flush is performed, the entity will be updated in the database. This seems reasonable to me, because when you make an entity managed, you actually want the EntityManager to manage it ;)
In your case you only need the entity for an association with another entity, so you don't really need it to be managed. I therefor suggest a different approach.
Use a reference
So don't merge $contest back into the EntityManager, but grab a reference to it:
$contest = $cacheDriver->fetch($key);
$contestRef = $em->getReference('Contest', $contest->getId());
$contestRegistry = new ContestRegistry();
$contestRegistry->setContest($contestRef);
$em->persist($contestRegistry);
$em->flush();
That reference will be a Proxy (unless it's already managed), and won't be loaded from the db at all (not even when flushing the EntityManager).
Result Cache
In stead of using you own caching mechanisms, you could use Doctrine's result cache. It caches the query results in order to prevent a trip to the database, but (if I'm not mistaken) still hydrates those results. This prevents a lot of issues that you can get with caching entities themselves.
What you want to achieve is called partial update.
You should use something like this instead
/**
* Partially updates an entity
*
* #param Object $entity The entity to update
* #param Request $request
*/
protected function partialUpdate($entity, $request)
{
$parameters = $request->request->all();
$accessor = PropertyAccess::createPropertyAccessor();
foreach ($parameters as $key => $parameter) {
$accessor->setValue($entity, $key, $parameter);
}
}
Merge requires the whole entity to be 100% fullfilled with data.
I haven't checked the behavior with children (many to one, one to one, and so on) relations yet.
Partial update is usually used on PATCH (or PUT) on a Rest API.

Symfony2 - mapping two tables

I want to join two tables (games and ownership). From there, I want to print those Games which user has assigned to him in Ownership. For example: user (id: 2) has two games (id: 1 and id:2). I want to print only these two.
My controller is as follows:
function getGameAction($id) {
$game = $this->getDoctrine()
->getRepository('GameShelfGamesBundle:Game')
->find($id);
return new Response($game->getOwnership()->getName());
}
Entities: Ownership and Game.
For now, I only get an error:
Fatal error: Call to undefined method Proxies__CG__\GameShelf\UsersBundle\Entity\Ownership::getName() in D:!!XAMPP\htdocs\Symfony\src\GameShelf\GamesBundle\Controller\DefaultController.php on line 50
Look at error message - you don't have either any getOwnership method or even relation with ownership table.
For first you need in you game entity declare relation with ownership:
/*
* #ORM\ManyToOne(targetEntity="Namespace\To\Ownership", inversedBy="games")
* #ORM\JoinColumn(name="ownership_id", referencedColumnName="id")
*/
private $ownership;
And in your Ownership entity:
/**
* #ORM\OneToMany(targetEntity="Namespace\To\Game", mappedBy="ownership")
*/
private $games;
Then run console command to generate setters and getters and everything should goes fine.
You just forgot to add a variable named "name" in your Ownership-Entity. Therefore you don't have any getters and setters automatically generated.
Try to put all your variables at the beginning of your code #Cyprian oversaw your relation because of that.
If you just look at the errormessage you should instantly see where your error is coming from.

Categories