doctrine / DoctrineFixturesBundle

Symfony integration for the doctrine/data-fixtures library
MIT License
2.46k stars 203 forks source link

Default entity manager always used in fixtures ? #236

Open Glideh opened 6 years ago

Glideh commented 6 years ago

I have multiple connections used by multiple entity managers with separate bundles (Symfony 3.4):

doctrine:
    dbal:
        default_connection: cnx1
        connections:
            cnx1:
#              ...
            cnx1:
#              ...
#           ...
    orm:
        default_entity_manager: em1
        entity_managers:
            em1:
                connection: cnx1
                mappings:
                    FirstBundle: ~
            em2:
                connection: cnx2
                mappings:
                    SecondBundle: ~
#           ...

I have fixtures in both, but Doctrine seem to use only the default entity manager for both.

$ console doctrine:fixtures:load -n

  > purging database
  > loading FirstBundle\DataFixtures\ORM\LoadEntity1Data
  > loading FirstBundle\DataFixtures\ORM\LoadEntity2Data
[...]
  > loading SecondBundle\DataFixtures\ORM\LoadEntity3Data

In MappingException.php line 37:

The class 'SecondBundle\Entity\Entity3' was not found
  in the chain configured namespaces FirstBundle\Entity

Is there a way to help Doctrine in our fixtures guessing which manager to use ? This would avoid to have to use this for each distinct entity manager.

$ console doctrine:fixtures:load -n --em=em1 --fixtures=src/FirstBundle/DataFixtures/ORM
$ console doctrine:fixtures:load -n --em=em2 --fixtures=src/SecondBundle/DataFixtures/ORM

Maybe there is some simpler way I'm not aware of.

weaverryan commented 6 years ago

At first glance, I think this should totally be possible. There is a method on the Registry class called getManagerForClass() that could be used:

https://github.com/doctrine/common/blob/a61bfddd39b887265117806e81cc6ca8da242fe1/lib/Doctrine/Common/Persistence/AbstractManagerRegistry.php#L171

Someone care to open a PR?

migueabellan commented 5 years ago

As a possible solution, while the issue is solved, you can use groups in fixtures:

https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html#fixture-groups-only-executing-some-fixtures

Later, you can exec fixtures as:

$ php bin/console doctrine:fixtures:load --em em1 --group=em1 --no-interaction
$ php bin/console doctrine:fixtures:load --em em2 --group=em2 --no-interaction

This works for me on Symfony 4.2 :+1:

alcaeus commented 5 years ago

For now, groups seem to be the only way this can be done reliably. In fixture services, you could easily have the manager registry injected and then select the appropriate manager using the getManagerForClass method that @weaverryan mentioned above. However, the fixtures will always be run in the transactional context of the entity manager provided to the command (or the default entity manager if none was provided), so you'll have to take care of transactional logic yourself.

I'm not sure what a good way to solve this would be, apart from what @migueabellan suggested above.

skylord123 commented 4 years ago

@alcaeus Don't we just change the default behavior so when an entity manager isn't specified we try to auto detect it for the objects?

I just ran into this problem and the fix is pretty gross. I expected it to auto detect when not specifying the entity manager.

alcaeus commented 4 years ago

The fixtures only receive a single entity manager. It is up to the fixture itself to ensure that the entity manager can actually handle the entity you want to create.

When using multiple entity managers, it would definitely be advantageous to pass in the entire manager registry. I'm not sure how we can accomplish that without a hard BC break, but it could be a way to get rid of the em setting entirely.