Hey,
as there was a question about how to implement an own repository factory within laminas / mezzio to realize custom dependencies in a constructor of a doctrine entity repository, which was deleted by the author, I wrote this small example.
Doctrine uses it 's own repository factory, which you can override in your doctrine config with your own respository factory. Having a look into the original doctrine repository factory you only have to implement the RepositoryFactory
interface.
Your custom factory
You just write your own repository factory, which you 'll use for your repositories with dependencies in the future.
<?php
declare(strict_types=1);
namespace Marcel\ORM\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Repository\RepositoryFactory;
use Psr\Container\ContainerInterface;
class MyCustomRepositoryFactory implements RepositoryFactory
{
protected array $repositoryList = [];
public function __construct(
protected ContainerInterface $container,
) {}
public function getRepository(
EntityManagerInterface $entityManager,
string $entityName
): EntityRepository
{
$repositoryHash = $entityManager
->getClassMetadata($entityName)
->getName() . spl_object_hash($entityManager);
if (isset($this->repositoryList[$repositoryHash])) {
return $this->repositoryList[$repositoryHash];
}
return $this->repositoryList[$repositoryHash] =
$this->createRepository($entityManager, $entityName);
}
protected function createRepository(
EntityManagerInterface $entityManager,
string $entityName
): EntityRepository
{
$metadata = $entityManager->getClassMetadata($entityName);
$repositoryClassName = $metadata->customRepositoryClassName
?: $entityManager
->getConfiguration()
->getDefaultRepositoryClassName();
// here 's the magic
// the service manager recognizes the fqcn of the repository and checks if a
// factory was configured for this repository
return ($this->container->has($repositoryClassName)
? $this->container->get($repositoryClassName);
: new $repositoryClassName($entityManager, $metadata);
}
}
Factory for your repository factory
Since your custom factory has a dependency to the service container you have to write a factory for the factory. After all these years using Zend / Laminas I still feel a bit uncomfy with factories for factories. But that 's the way it works I guess. If anyone has a better approach I 'd be curious to read about it.
<?php
declare(strict_types=1);
namespace Marcel\ORM\Repository\Factory;
use Marcel\ORM\Repository\MyCustomRepositoryFactory;
use Psr\Container\ContainerInterface;
class MyCustomRepositoryFactoryFactory
{
public function __invoke(
ContainerInterface $container
): MyCustomRepositoryFactory
{
$factory = new MyCustomRepositoryFactory($container);
return $factory;
}
}
Service manager config
As always factories have to be registered in the service manager via config.
...
'service_manager' => [
ORM\Repository\MyCustomRepositoryFactory::class
=> ORM\Repository\Factory\MyCustomRepositoryFactoryFactory::class,
],
...
Doctrine config
Finally edit your doctrine config
'doctrine' => [
'configuration' => [
'orm_default' => [
'repository_factory' => ORM\Repository\MyCustomRepositoryFactory::class,
],
],
]
Code is not tested.