Skip to content

Commit

Permalink
Extract configuration-related code from EntityManagerFactory into Con…
Browse files Browse the repository at this point in the history
…figurationFactory
  • Loading branch information
acelaya committed Oct 27, 2024
1 parent 57bac8c commit 79caaa1
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 94 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).

## [Unreleased]
### Added
* *Nothing*

### Changed
* Extract configuration-related code from `EntityManagerFactory` into `ConfigurationFactory`.

### Deprecated
* *Nothing*

### Removed
* *Nothing*

### Fixed
* *Nothing*


## [6.4.0] - 2024-10-27
### Added
* Add support for `endroid/qr-code` 6.0
Expand Down
2 changes: 2 additions & 0 deletions config/doctrine.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Shlinkio\Shlink\Common;

use Doctrine\DBAL\Connection;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;

return [
Expand All @@ -19,6 +20,7 @@

'dependencies' => [
'factories' => [
Configuration::class => Doctrine\ConfigurationFactory::class,
EntityManager::class => Doctrine\EntityManagerFactory::class,
Connection::class => Doctrine\ConnectionFactory::class,
Doctrine\NoDbNameConnectionFactory::SERVICE_NAME => Doctrine\NoDbNameConnectionFactory::class,
Expand Down
55 changes: 55 additions & 0 deletions src/Doctrine/ConfigurationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Shlinkio\Shlink\Common\Doctrine;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Configuration;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Container\ContainerInterface;
use Shlinkio\Shlink\Common\Doctrine\Mapping\EnhancedPHPDriver;

class ConfigurationFactory
{
public function __invoke(ContainerInterface $container): Configuration
{
$globalConfig = $container->get('config');
$isDevMode = (bool) ($globalConfig['debug'] ?? false);
$cache = $container->get(CacheItemPoolInterface::class);
$emConfig = $globalConfig['entity_manager'] ?? [];
$ormConfig = $emConfig['orm'] ?? [];
$funcStyle = $ormConfig['load_mappings_using_functional_style'] ?? false;
$defaultRepo = $ormConfig['default_repository_classname'] ?? null;

$this->registerTypes($ormConfig);

$config = new Configuration();
$config->setMetadataCache($cache);
$config->setQueryCache($cache);
$config->setResultCache($cache);
$config->setProxyDir($ormConfig['proxies_dir'] ?? '');
$config->setProxyNamespace('DoctrineProxies');
$config->setAutoGenerateProxyClasses($isDevMode);
$config->setMetadataDriverImpl(
new EnhancedPHPDriver($ormConfig['entities_mappings'] ?? [], $emConfig, $funcStyle),
);

if ($defaultRepo !== null) {
$config->setDefaultRepositoryClassName($defaultRepo);
}

return $config;
}

private function registerTypes(array $ormConfig): void
{
$types = $ormConfig['types'] ?? [];

foreach ($types as $name => $className) {
if (! Type::hasType($name)) {
Type::addType($name, $className);
}
}
}
}
55 changes: 5 additions & 50 deletions src/Doctrine/EntityManagerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,29 @@
namespace Shlinkio\Shlink\Common\Doctrine;

use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Container\ContainerInterface;
use Shlinkio\Shlink\Common\Doctrine\Mapping\EnhancedPHPDriver;

class EntityManagerFactory
{
public function __invoke(ContainerInterface $container): EntityManager
{
$globalConfig = $container->get('config');
$isDevMode = (bool) ($globalConfig['debug'] ?? false);
$cache = $container->get(CacheItemPoolInterface::class);
$ormConfig = $container->get(Configuration::class);

$emConfig = $globalConfig['entity_manager'] ?? [];
$connectionConfig = $emConfig['connection'] ?? [];
$ormConfig = $emConfig['orm'] ?? [];
$funcStyle = $ormConfig['load_mappings_using_functional_style'] ?? false;
$defaultRepo = $ormConfig['default_repository_classname'] ?? null;

$this->registerTypes($ormConfig);

$config = $this->createConfiguration($isDevMode, $ormConfig['proxies_dir'] ?? '', $cache);
$config->setMetadataDriverImpl(
new EnhancedPHPDriver($ormConfig['entities_mappings'] ?? [], $emConfig, $funcStyle),
);

if ($defaultRepo !== null) {
$config->setDefaultRepositoryClassName($defaultRepo);
}
$em = new EntityManager(DriverManager::getConnection($connectionConfig, $ormConfig), $ormConfig);

$em = new EntityManager(DriverManager::getConnection($connectionConfig, $config), $config);

$this->registerListeners($ormConfig, $em, $container);
$this->registerListeners($emConfig['orm']['listeners'] ?? [], $em, $container);

return $em;
}

private function registerTypes(array $ormConfig): void
{
$types = $ormConfig['types'] ?? [];

foreach ($types as $name => $className) {
if (! Type::hasType($name)) {
Type::addType($name, $className);
}
}
}

private function createConfiguration(bool $isDev, string $proxyDir, CacheItemPoolInterface $cache): Configuration
private function registerListeners(array $listeners, EntityManager $em, ContainerInterface $container): void
{
$config = new Configuration();

$config->setMetadataCache($cache);
$config->setQueryCache($cache);
$config->setResultCache($cache);
$config->setProxyDir($proxyDir);
$config->setProxyNamespace('DoctrineProxies');
$config->setAutoGenerateProxyClasses($isDev);

return $config;
}

private function registerListeners(array $ormConfig, EntityManager $em, ContainerInterface $container): void
{
$listeners = $ormConfig['listeners'] ?? [];
$events = $em->getEventManager();

foreach ($listeners as $event => $services) {
foreach ($services as $service) {
$events->addEventListener($event, $container->get($service));
Expand Down
106 changes: 106 additions & 0 deletions test/Doctrine/ConfigurationFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace ShlinkioTest\Shlink\Common\Doctrine;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\Mapping\Driver\PHPDriver;
use Laminas\ServiceManager\ServiceManager;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemPoolInterface;
use ReflectionObject;
use Shlinkio\Shlink\Common\Doctrine\ConfigurationFactory;
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
use ShlinkioTest\Shlink\Common\Repository\CustomRepository;
use Symfony\Component\Cache\Adapter\ArrayAdapter;

use function array_filter;
use function array_merge;
use function array_merge_recursive;

use const ARRAY_FILTER_USE_KEY;

class ConfigurationFactoryTest extends TestCase
{
private ConfigurationFactory $factory;

public function setUp(): void
{
if (Type::hasType(ChronosDateTimeType::CHRONOS_DATETIME)) {
$typeRegistry = Type::getTypeRegistry();
$ref = new ReflectionObject($typeRegistry);
$instancesProp = $ref->getProperty('instances');
$instancesProp->setAccessible(true);
$withoutChronosType = array_filter(
$typeRegistry->getMap(),
fn (string $key): bool => $key !== ChronosDateTimeType::CHRONOS_DATETIME,
ARRAY_FILTER_USE_KEY,
);
$instancesProp->setValue($typeRegistry, $withoutChronosType);
}

$this->factory = new ConfigurationFactory();
}

#[Test, DataProvider('provideConfig')]
public function serviceIsCreated(
array $config,
int $expectedAutoGenerateProxies,
string $expectedDefaultRepo,
): void {
$sm = new ServiceManager(['services' => [
'config' => $config,
CacheItemPoolInterface::class => new ArrayAdapter(),
]]);

self::assertFalse(Type::hasType(ChronosDateTimeType::CHRONOS_DATETIME));
$config = ($this->factory)($sm);

self::assertTrue(Type::hasType(ChronosDateTimeType::CHRONOS_DATETIME));
self::assertEquals($expectedAutoGenerateProxies, $config->getAutoGenerateProxyClasses());
self::assertEquals(__DIR__, $config->getProxyDir());
self::assertEquals($expectedDefaultRepo, $config->getDefaultRepositoryClassName());

/** @var PHPDriver $metaDriver */
$metaDriver = $config->getMetadataDriverImpl();
self::assertEquals([__FILE__], $metaDriver->getLocator()->getPaths());
}

public static function provideConfig(): iterable
{
$baseConfig = [
'entity_manager' => [
'orm' => [
'types' => [
ChronosDateTimeType::CHRONOS_DATETIME => ChronosDateTimeType::class,
],
'proxies_dir' => __DIR__,
'entities_mappings' => [__FILE__],
],
'connection' => [
'driver' => 'pdo_sqlite',
],
],
];

yield [array_merge($baseConfig, ['debug' => true]), 1, EntityRepository::class];
yield [array_merge($baseConfig, ['debug' => '1']), 1, EntityRepository::class];
yield [array_merge($baseConfig, ['debug' => 'true']), 1, EntityRepository::class];
yield [array_merge($baseConfig, ['debug' => false]), 0, EntityRepository::class];
yield [array_merge($baseConfig, ['debug' => null]), 0, EntityRepository::class];
yield [array_merge($baseConfig, ['debug' => null]), 0, EntityRepository::class];
yield [
array_merge_recursive($baseConfig, [
'entity_manager' => [
'orm' => ['default_repository_classname' => CustomRepository::class],
],
]),
0,
CustomRepository::class,
];
}
}
Loading

0 comments on commit 79caaa1

Please sign in to comment.