-
-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple doctrine entity manager instances #99
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm 👍 for the feature, thank you a lot for the PR! I would however:
- Try the suggestion regarding the constructor without which it's a BC break and would require a version bump which I would like to avoid if possible
- I would like to see a test for it as well; You can add it to
ObjectManagerPersisterTest
. The DB configuration can be found inautoload.php
and amake test_doctrine_bridge
should run all the right tests without you having to worry about setting up dependencies (it does require you to install a local DB instance though
@@ -71,7 +71,7 @@ | |||
<service id="fidry_alice_data_fixtures.persistence.persister.doctrine_mongodb.object_manager_persister" | |||
class="Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister" | |||
lazy="true"> | |||
<argument type="service" id="doctrine_mongodb.odm.document_manager" /> | |||
<argument type="service" id="doctrine" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this would be a different one no? doctrine
is for the ORM Registry isn't it?
Same comment for the two occurrences below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be doctrine_mongodb
, same for the purger and purger_factory
@@ -30,7 +31,8 @@ | |||
{ | |||
use IsAServiceTrait; | |||
|
|||
private $objectManager; | |||
/** @var array|ObjectManager[] */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can omit array
here
@@ -42,9 +44,9 @@ | |||
*/ | |||
private $metadata = []; | |||
|
|||
public function __construct(ObjectManager $manager) | |||
public function __construct(ManagerRegistry $managerRegistry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a more BC friendly way would be to inject directly the managers:
function __construct(ObjectManager ...$managers) {
$this->managers = $managers;
}
Since the service is lazy it shouldn't cause any issue. This may require an extra dependency with the expression language though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the ManagerRegistry
allow to call $this->managerRegistry->getManagerForClass($class);
directly, wich remove a lot of complexity. See below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah @jdeniau is right, having the ManagerRegistry
is nice to remove some complexity.
What should we do ? ObjectManager ...$managers
with some complexity but no BC or ManagerRegistry $managerRegistry
with reduced complexity but BC. Up to you @theofidry .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can the registry be instantiated here since we cannot inject it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instantiated ? You mean make a new ManagerRegistry()
inside the constructor ? it seems hard, see the service declaration : https://github.com/doctrine/DoctrineBundle/blob/master/Resources/config/dbal.xml#L59L65
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the implementation: https://github.com/doctrine/persistence/blob/master/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php#L156
I don't think iterating over the managers is a bad idea in the end. Maybe you can create a custom ManagerRegistry
class to be able to cache the results a bit like we are doing for the metadata, which you then can instantiate more easily
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about it again, what about have a dedicated class implementing ObjectManager
?
class ObjectsManager implements ObjectManager {
function (ManagerRegistry $registry) {
$this->registry = $registry;
}
function getClassMetadata(string $class): Metadata {
$manager = $this->managerRegistry->getManagerForClass($class)
$manager->getClassMetadata($class);
}
}
So that manager can take the registry just fine and we can inject this new manager without any BC breaks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think ObjectManager[]
would be the best approach since it allows to push managers from both ORM and ODM together, you can iterate them and treat them the same regardless where they came from.
Nope, injecting managers alone is not enough since you can't ask the manager if it is managing a specific class, the only place where this info is available is the registry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi. I don't know if my comment would help but injecting the registry and getting a fresh manager each time you want to persist will also allow insert errors. Usually as soon as the database throws an error, the manager closes. The only way to re-open the connection is to get a fresh manager from the registry. Keeping in mind this I would suggest to inject the registry instead of all the managers.
Note: I'm trying to fix the tests on master (it should be failures related to deprecation notices, but the tests themselves are fine so you can still see the results locally) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to compare with master...jdeniau:jd-feat-multipleDoctrineOrmV2 if you need help
@@ -53,7 +55,7 @@ public function __construct(ObjectManager $manager) | |||
public function persist($object) | |||
{ | |||
if (null === $this->persistableClasses) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use $objectManager = $this->managerRegistry->getManagerForClass($class);
with remove all the complexity of persistableClass
.
It returns ObjectManager|null
@@ -42,9 +44,9 @@ | |||
*/ | |||
private $metadata = []; | |||
|
|||
public function __construct(ObjectManager $manager) | |||
public function __construct(ManagerRegistry $managerRegistry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the ManagerRegistry
allow to call $this->managerRegistry->getManagerForClass($class);
directly, wich remove a lot of complexity. See below
} catch (ORMException $exception) { | ||
if ($metadata->idGenerator instanceof ORMAssignedGenerator) { | ||
throw ObjectGeneratorPersisterExceptionFactory::createForEntityMissingAssignedIdForField($object); | ||
foreach ($this->managers as $manager) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then, as you have an entity manager, you just need to do $objectManager->persist($object)
.
@@ -130,8 +143,11 @@ private function getPersistableClasses(ObjectManager $manager): array | |||
private function getMetadata(string $class): ClassMetadata |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here, you can inject the ObjectManager and get metadata directly with $objectManager->getMetadata($class)
@@ -73,7 +73,7 @@ | |||
<service id="fidry_alice_data_fixtures.persistence.persister.doctrine_phpcr.object_manager_persister" | |||
class="Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister" | |||
lazy="true"> | |||
<argument type="service" id="doctrine_phpcr.odm.document_manager" /> | |||
<argument type="service" id="doctrine" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be doctrine_phpcr
, same with the purger and purger_factory
@@ -71,7 +71,7 @@ | |||
<service id="fidry_alice_data_fixtures.persistence.persister.doctrine_mongodb.object_manager_persister" | |||
class="Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister" | |||
lazy="true"> | |||
<argument type="service" id="doctrine_mongodb.odm.document_manager" /> | |||
<argument type="service" id="doctrine" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be doctrine_mongodb
, same for the purger and purger_factory
I've made an update to the PR, it's still WIP but suggestions are welcomed.
|
|
||
/** | ||
* @var ClassMetadata[] Entity metadata, FQCN being the key | ||
* @var string[ObjectManager] Keys are FQCN of persistable objects, Values are managers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's a valid phpdoc type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't know if it's possible to set the type of keys
|
||
public function __construct(ObjectManager $manager) | ||
public function __construct(ObjectManager ...$managers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically, this allows to pass no manager at all (a variable argument is 0+, not 1+)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well this was a suggestion from @theofidry as I injected the ManagerRegistry in my first commit.
With this and the fact that we can't inject %doctrine.entity_managers%
it seems it's not possible to use ObjectManager ...$managers
. Any thought ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, if you want to keep a variadic constructor, you will need an argument to add all the relevant references as arguments in your service definition.
$this->managers = $managers; | ||
|
||
foreach ($managers as $manager) { | ||
$allMetadata = $manager->getMetadataFactory()->getAllMetadata(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loading all metadata of a manager is bad for performance, as this is not an optimized API. The optimized API is the one getting metadata for a given class (as the class name is the cache key).
It would be better to build the map on demand, when being asked for a specific class, rather than trying to build it upfront
@@ -71,7 +72,7 @@ | |||
<service id="fidry_alice_data_fixtures.persistence.persister.doctrine_mongodb.object_manager_persister" | |||
class="Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister" | |||
lazy="true"> | |||
<argument type="service" id="doctrine_mongodb.odm.document_manager" /> | |||
<argument>%doctrine_mongodb.odm.document_managers%</argument> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that won't work. As you made the constructor variadic, you need to add many arguments.
and btw, this parameters contains the names of document managers, not the objects (a parameter cannot contain references to services)
@@ -79,7 +80,7 @@ | |||
<service id="fidry_alice_data_fixtures.persistence.persister.doctrine.object_manager_persister" | |||
class="Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister" | |||
lazy="true"> | |||
<argument type="service" id="doctrine.orm.entity_manager" /> | |||
<argument>%doctrine.entity_managers%</argument> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same issue here than for the ODM
@@ -73,7 +75,7 @@ | |||
<service id="fidry_alice_data_fixtures.persistence.persister.doctrine_phpcr.object_manager_persister" | |||
class="Fidry\AliceDataFixtures\Bridge\Doctrine\Persister\ObjectManagerPersister" | |||
lazy="true"> | |||
<argument type="service" id="doctrine_phpcr.odm.document_manager" /> | |||
<argument>%doctrine_phpcr.odm.document_managers%</argument> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and again here
Btw, the issues I reported are telling me that I don't agree with your checked "Test it works with one manager" (and Travis agrees with me, not with you, as CI is failing) |
You are right, too much multi-tasking made me forgot to change the service declaration in my test env :( |
@theofidry Any idea on what is the cause of the fail ? |
No idea, would need to dig into it but cannot at the moment. I would suggest to carry on and I can dig into it after the reviews to see what is causing an issue |
Might be a nice way of dealing with it.
The interface is quite complex (13 methods), but all are probably not used
if the class is internal
…On Mon, Sep 24, 2018 at 8:41 PM Théo FIDRY ***@***.***> wrote:
No idea, would need to dig into it but cannot at the moment. I would
suggest to carry on and I can dig into it after the reviews to see what is
causing an issue
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#99 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABVWxRIhY5oF-Y4CXUGHBwZSFASufdcGks5ueSdigaJpZM4WhxAa>
.
|
Yes, you could throw a |
This looks like it's mostly finished or am I missing something? |
It still needs https://github.com/theofidry/AliceDataFixtures/pull/99/files#r219945408 + making the tests greens, but otherwise yeah we are not far off having it merged |
Note, my first reason for asking about this was to allow me to load ORM and ODM fixtures at the same time (ODM references ORM). Looking at |
BTW the ODM documents are already properly constructed by |
Yes, and potentially can be switched to be the new default command, i.e.
I think there is an open issue about the ORM not having its manager properly propagated, i.e. the right manager is used for loading but not purging. I'm not aware of an issue for the ODM so if there is one an issue should be opened for it |
Here's a quick hack to illustrate the required points, continuation from our Slack conversation: For the feature to work, the new @theofidry do you have any comments there or here? /cc @mleczakm |
Hi,
This should be fixed in #113
|
Fixes #90, based on #96