I wanted to be able to use Doctrine multiple managers setup and all codeception methods with it but it kept breaking (didn't see set attributes, worked only on default manager etc.) and this is what I came up with:
In a Helper I've created method for setting doctrine manager service using Symfony module:
class Shared extends \Codeception\Module
{
public \Doctrine\ORM\EntityManagerInterface $em;
/**
* @param string $emAlias Name of your entity manager in doctrine.yaml
*/
public function changeEm(string $emAlias): void
{
if ('internal' !== $connection && 'api' !== $emAlias) {
throw new \Error('Unknown connection: ' . $emAlias);
}
$doctrine = $this->getService(ManagerRegistry::class);
$em = $doctrine->getManager($emAlias);
// We need to verify that connection is open as it gets shut down on error
if (!$em->isOpen()) {
$doctrine->resetManager($emAlias);
}
$this->setEm($em, $emAlias);
}
public function setEm(EntityManagerInterface $em, string $emAlias): void
{
$this->em = $em; // Just to be safe and have access to selected entity
$this->getModule('Doctrine2')->em = $em;
$sfModule = $this->getModule('Symfony');
/** @var \Symfony\Bundle\FrameworkBundle\Test\TestContainer $container */
$container = $sfModule->_getContainer();
$service = 'doctrine.orm.' . $emAlias . '_entity_manager';
if ($container->initialized($service)) {
return;
}
$container->set($service, $em);
$sfModule->persistService($service, true);
}
}
and with that always set default entity manager at the top of method shared by all your tests (which is, in my case, _before in tests parent class):
abstract class BaseCestAbstract
{
public function _before(ApiTester $I): void
{
$I->changeEm('internal'/'api');
[...]
}
}
And now if you want to change manager Codeception is using mid-test:
public function testA(ApiTester $I): void
{
$I->changeEm('internal');
[...]
$I->changeEm('api');
[...]
}
all methods like grabEntityFromRepository
should be working and secondary booted Kernel for API calls should be using the same entity as you.
Drawbacks:
I couldn't figure out how to make it work with cleanup: true
which is a pain, but I mainly use it for REST calls which don't really work with cleanup anyway, so it is acceptable in my case.
Versions:
- Symfony: 6.2.6
- Codeception: 5.0.8
- codeception/module-doctrine2: 3.0.1
- doctrine/doctrine-bundle: 2.8.3