multiple entitymanager symfony - symfony

Before I used only one entity manager to interact with my database.
Everything worked well till I add 2 new entity manager (one entity manager to insert data and one entity manager to select data)
-> I want to make a replication of my database later.
I think, I can solve the problem alone, but I just want to understand why this error appears :
A new entity was found through the relationship 'AppBundle\Entity\Userinterest#user'
that was not configured to cascade persist operations for entity: my_username.
To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity
or configure cascade persist this association in the mapping for example
#ManyToOne(..,cascade={"persist"})
I think, I understand the problem :) :
My User from FOSUserBundle is authenticate with the default entity manager.
$userinteret->setUser($this->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($userinteret);
$em->flush();
Then, I don't know how is stored the token_storage. But because I use the user from the token_storage, I think the probem come from there.

Try with :
// All 3 return the "default" entity manager
$em = $this->getDoctrine()->getManager();
$em = $this->getDoctrine()->getManager('default');
$em = $this->get('doctrine.orm.default_entity_manager');
// Both of these return the "customer" entity manager
$customerEm = $this->getDoctrine()->getManager('customer');
$customerEm = $this->get('doctrine.orm.customer_entity_manager');
How to Work with multiple Entity Managers and Connections

Related

Symfony2, KnpLabs DoctrineBehaviors: How do I truly delete a softdeletable entity?

Is there a way to override the softdeletable behaviour with KNPLabs DoctrineBehaviors from a controller?
In my action, I would like to be able to momentarily "disable" the softdeletable behaviour so I can truly remove my entity from the database instead of just setting the deletedAt field.
nifr kindly gave me an answer on Github:
https://github.com/KnpLabs/DoctrineBehaviors/issues/294#issuecomment-190310921:
Quick 'n dirty:
$entityManager = $this->getDoctrine()->getManager('default');
$eventManager = $entityManager->getEventManager();
// remove the softdeletable subscriber
$subscriber = $this->get('knp.doctrine_behaviors.softdeletable_subscriber');
$eventManager->removeEventListener($subscriber->getSubscribedEvents(), $subscriber);
// remove entity while the subscriber is removed
$entityManager->remove($entity);
$entityManager->flush();
// add back the subscriber
$eventManager->addEventSubscriber($subscriber);
PROBLEM
This triggers the error "you have requested a non-existent service", because the service is not public.
To resolve this issue, according to nifr, 2 possible solutions:
1) define your controller itself as a service and inject the subscriber-service explicitly
2) create a factory-service that would return the subscriber service and call that one in your controller

Symfony2 - How to Dynamically get a Doctrine entity's Entity Manager

We are building a CMS and website building platform with a lot of different vendors and clients sites, so there are a lot of different content type entities, which are edited by generic controllers and helper services that don't necessarily (easily) know what the entity manager is for a given entity.
NOTE: We have several entityManagers to separate access to different databases, e.g. Global, Billing, Local, etc
There are many cases where we need to detect what is the entity's EntityManager. For example, we have a MediaHelper that dynamically associates media from a database with matching fields on the entity (this doesn't work with associations because the Media has to connect with literally any entity and you can't have that kind of dynamic association and we don't want a hundred different associations).
The media is in a bundle managed by the 'Local' EntityManager. But the entity may be in a 'Global' EntityManager (you can't assume it's in the same entity manager). So we need to detect and persist the right entity manager for the right entity.
So how do you recommend dynamically detecting the entityManager for an entity?
Original Custom Method
NOTE: the accepted answer is a much better solution. This is just here for archival purposes.
Here is a simple solution that works. But I don't know enough about Symfony and Doctrine to know if it's a bad idea? Does anyone else know? If not, I don't know why this wouldn't be in the core, as a Doctrine Utility.
I created an EntityHelper service that injects the Doctrine service into it:
gutensite_cms.entity_helper:
class: Gutensite\CmsBundle\Service\EntityHelper
arguments:
- "#doctrine"
Then in the entity helper is one simple function to get the Entity Manager for an entity (the config.yml registers the bundles for entity managers already):
/**
* Automagically find the entityManager for an entity.
* #param $entity
* #return mixed
*/
public function getManagerForEntity($entity) {
$className = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity));
foreach (array_keys($this->doctrine->getManagers()) as $name) {
if(in_array($className, $this->doctrine->getManager($name)->getConfiguration()->getMetadataDriverImpl()->getAllClassNames())) return $em;
}
}
NOTE: Doctrine Registry#getAliasNamespace already does something nearly identical to this foreach loop, I just modified the idea to return the entity manager instead of the namespace, e.g.
public function getAliasNamespace($alias) {
foreach (array_keys($this->getManagers()) as $name) {
try {
return $this->getManager($name)->getConfiguration()->getEntityNamespace($alias);
} catch (ORMException $e) {
}
}
throw ORMException::unknownEntityNamespace($alias);
}
Update 10/21/15: Entity Detection Code updated per #Cerad's suggestion.
Per the suggestion of #qooplmao, there is an easy method already in the Doctrine core.
// 1) get the real class for the entity with the Doctrine Utility.
$class = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($entity))
// 2) get the manager for that class.
$entityManager = $this->container->get('doctrine')->getManagerForClass($class);
Updated 10/22/15 After suggestions from Cerad and Qooplmao
Can you not give the entity manager a alias that suits the context it is for? You talk about Global, Billing, Local, so for example:
'service_manager' => array(
'aliases' => array(
'global_entity_manager' => 'My\Global\EntityManager',
'billing_entity_manager' => 'My\Billing\EntityManager',
'local_entity_manager' => 'My\Local\EntityManager',
),
)
You could also map the entity manager to the namespace of the entity.
So let's say you have a folder for your Global entities that is Global\Entity, then you could alias the entity manager for those entities Global\Entity\EntityManager. The advantage of this solution is that you can map several namespaces to the same entity manager, so your Billing and Global entities can easily share the same entity manager:
'service_manager' => array(
'aliases' => array(
'Global\Entity\EntityManager' => 'My\Global\EntityManager',
'Billing\Entity\EntityManager' => 'My\Global\EntityManager', // <-same name
'Local\Entity\EntityManager' => 'My\Local\EntityManager',
),
)
This only works if your entities in one namespace are manager by the same EntityManager instance. I can hardly believe this would not be the case in any project, but otherwise you should maybe reorganize a bit? :D

Doctrine "A new entity was found through the relationship" error

First off I want to say I've read through all the docs and googled this plenty before posting this question. I know what that error means (un-persisted entity in a relationship)
I'm getting this error where I think I shouldn't be getting it.
I have a OneToMany Bi-Directional relationship as follow:
Class Channel
{
/**
* #ORM\OneToMany(targetEntity="Step", mappedBy="channel", cascade={"all"}, orphanRemoval=true)
* #ORM\OrderBy({"sequence" = "ASC"})
*/
protected $steps;
}
Class Step
{
/**
* #ORM\ManyToOne(targetEntity="Channel", inversedBy="steps")
*/
protected $channel;
}
One Channel can have many Steps and the owning side is Channel. After I upgraded from Doctrine 2.4 to 2.5 I'm getting this error:
Doctrine\ORM\ORMInvalidArgumentException: A new entity was found
through the relationship 'Company\MyBundle\Entity\Step#channel' that
was not configured to cascade persist operations for entity
why is it even finding new relationships from the inverse side? Here's my code:
$channel = new Channel();
$step = new Step();
$channel->addStep($step);
$em->persist($channel);
$em->flush();
Thanks!
You're right: Doctrine looks only for changes into owning side but you're wrong: owning side of your relationship is Step, not Channel.
Why is step the owning side? Because is the entity that has foreign key. Even Doctrine documentation says to you
The owning side has to use the inversedBy attribute of the OneToOne,
ManyToOne, or ManyToMany mapping declaration. The inversedBy attribute
contains the name of the association-field on the inverse-side.
Possible solutions:
Try to invert cascade operations by putting cascade={"all"} into Step entity (are you sure that all is the correct choice?)
Persist explicitly both entities:
$channel = new Channel();
$step = new Step();
$channel->addStep($step);
$em->persist($channel);
$em->persist($step);
$em->flush();
here you can read why second way provided here is fine too
You try to persist $channel, but it has Step entity inside. So in Doctrine now you have 2 entities that are queued for inserting. Then Doctrine order entities in the order where first is Step because it has channel_id foreign key (that is empty now). Doctrine try persist this entity and when it understands that channel_id is empty it sees for cascade rules for persisting. It doesn't see any cascade rules and throw you this exception.

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

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

When to use Entity Manager in Symfony2

At the moment I am learning how to use Symfony2. I got to the point where they explain how to use Doctrine.
In the examples given they sometimes use the entity manager:
$em = $this->getDoctrine()->getEntityManager();
$products = $em->getRepository('AcmeStoreBundle:Product')
->findAllOrderedByName();
and in other examples the entity manager is not used:
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);
So I actually tried the first example without getting the entity manager:
$repository = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product');
$products = $repository->findAllOrderedByName();
and got the same results.
So when do i actually need the entity manager and when is it OK to just go for the repository at once?
Looking at Controller getDoctrine() equals to $this->get('doctrine'), an instance of Symfony\Bundle\DoctrineBundle\Registry. Registry provides:
getEntityManager() returning Doctrine\ORM\EntityManager, which in turn provides getRepository()
getRepository() returning Doctrine\ORM\EntityRepository
Thus, $this->getDoctrine()->getRepository() equals $this->getDoctrine()->getEntityManager()->getRepository().
Entity manager is useful when you want to persist or remove an entity:
$em = $this->getDoctrine()->getEntityManager();
$em->persist($myEntity);
$em->flush();
If you are just fetching data, you can get only the repository:
$repository = $this->getDoctrine()->getRepository('AcmeStoreBundle:Product');
$product = $repository->find(1);
Or better, if you are using custom repositories, wrap getRepository() in a controller function as you can get auto-completition feature from your IDE:
/**
* #return \Acme\HelloBundle\Repository\ProductRepository
*/
protected function getProductRepository()
{
return $this->getDoctrine()->getRepository('AcmeHelloBundle:Product');
}
I think that the getDoctrine()->getRepository() is simply a shortcut to getDoctrine()->getEntityManager()->getRepository(). Did not check the source code, but sounds rather reasonable to me.
If you plan to do multiple operations with the entity manager (like get a repository, persist an entity, flush, etc), then get the entity manager first and store it in a variable. Otherwise, you can get the repository from the entity manager and call whatever method you want on the repository class all in one line. Both ways will work. It's just a matter of coding style and your needs.

Resources