Skip to content

Commit 2c0b448

Browse files
committed
Issue #449: Implemented Doctrine table prefixes
Signed-off-by: alexmerlin <[email protected]>
1 parent 1a9383f commit 2c0b448

File tree

9 files changed

+117
-19
lines changed

9 files changed

+117
-19
lines changed

bin/doctrine

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
declare(strict_types=1);
55

6+
use Core\App\Event\TablePrefixEventListener;
7+
use Doctrine\ORM\Events;
68
use Doctrine\ORM\Tools\Console\ConsoleRunner;
79
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
810
use Dot\DataFixtures\Command\ExecuteFixturesCommand;
@@ -14,6 +16,8 @@ require_once 'vendor/autoload.php';
1416
$container = require 'config/container.php' ;
1517

1618
$entityManager = $container->get(EntityManager::class);
19+
$entityManager->getEventManager()
20+
->addEventListener(Events::loadClassMetadata, $container->get(TablePrefixEventListener::class));
1721

1822
$commands = [
1923
$container->get(ExecuteFixturesCommand::class),

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
"dotkernel/dot-maker": "^1.0.2",
8686
"laminas/laminas-coding-standard": "^3.0.1",
8787
"laminas/laminas-development-mode": "^3.13.0",
88-
"mezzio/mezzio-tooling": "^2.10.1",
8988
"phpstan/phpstan": "^2.1.11",
9089
"phpstan/phpstan-doctrine": "^2.0.2",
9190
"phpstan/phpstan-phpunit": "^2.0.6",

config/autoload/local.php.dist

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ $baseUrl = 'http://localhost:8080';
66

77
$databases = [
88
'default' => [
9-
'host' => 'localhost',
10-
'dbname' => 'dotkernel',
11-
'user' => '',
12-
'password' => '',
13-
'port' => 3306,
14-
'driver' => 'pdo_mysql',
15-
'charset' => 'utf8mb4',
16-
'collate' => 'utf8mb4_general_ci',
9+
'host' => 'localhost',
10+
'dbname' => 'dotkernel',
11+
'user' => '',
12+
'password' => '',
13+
'port' => 3306,
14+
'driver' => 'pdo_mysql',
15+
'charset' => 'utf8mb4',
16+
'collate' => 'utf8mb4_general_ci',
17+
'table_prefix' => 'dk_',
1718
],
1819
// you can add more database connections to this array
1920
];

config/cli-config.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@
22

33
declare(strict_types=1);
44

5+
use Core\App\Event\TablePrefixEventListener;
56
use Doctrine\Migrations\Configuration\EntityManager\ExistingEntityManager;
67
use Doctrine\Migrations\Configuration\Migration\ConfigurationArray;
78
use Doctrine\Migrations\DependencyFactory;
89
use Doctrine\ORM\EntityManager;
10+
use Doctrine\ORM\Events;
911

1012
$container = require 'config/container.php';
1113

14+
$entityManager = $container->get(EntityManager::class);
15+
$entityManager->getEventManager()
16+
->addEventListener(Events::loadClassMetadata, $container->get(TablePrefixEventListener::class));
17+
1218
return DependencyFactory::fromEntityManager(
1319
new ConfigurationArray($container->get('config')['doctrine']['migrations']),
14-
new ExistingEntityManager(
15-
$container->get(EntityManager::class)
16-
)
20+
new ExistingEntityManager($entityManager)
1721
);

config/config.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@
3131
Mezzio\Helper\ConfigProvider::class,
3232
Mezzio\ConfigProvider::class,
3333
Mezzio\Router\ConfigProvider::class,
34-
class_exists(Mezzio\Tooling\ConfigProvider::class)
35-
? Mezzio\Tooling\ConfigProvider::class
36-
: function () {
37-
return [];
38-
},
3934

4035
// Include cache configuration
4136
new Laminas\ConfigAggregator\ArrayProvider($cacheConfig),

log/.gitignore

100644100755
File mode changed.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Api\App\Factory;
6+
7+
use Core\App\Event\TablePrefixEventListener;
8+
use Doctrine\ORM\EntityManagerInterface;
9+
use Doctrine\ORM\Events;
10+
use Mezzio\Application;
11+
use Psr\Container\ContainerExceptionInterface;
12+
use Psr\Container\ContainerInterface;
13+
use Psr\Container\NotFoundExceptionInterface;
14+
15+
class TablePrefixDelegatorFactory
16+
{
17+
/**
18+
* @throws ContainerExceptionInterface
19+
* @throws NotFoundExceptionInterface
20+
*/
21+
public function __invoke(ContainerInterface $container, string $name, callable $callback): Application
22+
{
23+
if ($container->has('doctrine.entity_manager.orm_default')) {
24+
/** @var EntityManagerInterface $entityManager */
25+
$entityManager = $container->get('doctrine.entity_manager.orm_default');
26+
$entityManager->getEventManager()->addEventListener(
27+
Events::loadClassMetadata,
28+
$container->get(TablePrefixEventListener::class)
29+
);
30+
}
31+
32+
return $callback();
33+
}
34+
}

src/Core/src/App/src/ConfigProvider.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
namespace Core\App;
66

7+
use Api\App\Factory\TablePrefixDelegatorFactory;
78
use Core\App\Command\RouteListCommand;
89
use Core\App\DBAL\Types\SuccessFailureEnumType;
910
use Core\App\DBAL\Types\YesNoEnumType;
11+
use Core\App\Event\TablePrefixEventListener;
1012
use Core\App\Factory\EntityListenerResolverFactory;
1113
use Core\App\Resolver\EntityListenerResolver;
1214
use Core\App\Service\MailService;
@@ -23,6 +25,7 @@
2325
use Dot\Mail\Factory\MailOptionsAbstractFactory;
2426
use Dot\Mail\Factory\MailServiceAbstractFactory;
2527
use Dot\Mail\Service\MailService as DotMailService;
28+
use Mezzio\Application;
2629
use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType;
2730
use Ramsey\Uuid\Doctrine\UuidBinaryType;
2831
use Ramsey\Uuid\Doctrine\UuidType;
@@ -117,15 +120,19 @@ public function __invoke(): array
117120
private function getDependencies(): array
118121
{
119122
return [
120-
'factories' => [
123+
'delegators' => [
124+
Application::class => [TablePrefixDelegatorFactory::class],
125+
],
126+
'factories' => [
121127
'doctrine.entity_manager.orm_default' => EntityManagerFactory::class,
122128
'dot-mail.options.default' => MailOptionsAbstractFactory::class,
123129
'dot-mail.service.default' => MailServiceAbstractFactory::class,
124130
EntityListenerResolver::class => EntityListenerResolverFactory::class,
125131
MailService::class => AttributedServiceFactory::class,
126132
RouteListCommand::class => AttributedServiceFactory::class,
133+
TablePrefixEventListener::class => AttributedServiceFactory::class,
127134
],
128-
'aliases' => [
135+
'aliases' => [
129136
DotMailService::class => 'dot-mail.service.default',
130137
EntityManager::class => 'doctrine.entity_manager.orm_default',
131138
EntityManagerInterface::class => 'doctrine.entity_manager.orm_default',
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Core\App\Event;
6+
7+
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
8+
use Doctrine\ORM\Mapping\ClassMetadata;
9+
use Dot\DependencyInjection\Attribute\Inject;
10+
11+
use function array_key_exists;
12+
use function is_string;
13+
14+
class TablePrefixEventListener
15+
{
16+
private string $prefix = '';
17+
18+
/**
19+
* @phpstan-param array<non-empty-string, mixed> $config
20+
*/
21+
#[Inject(
22+
'config.doctrine.connection.orm_default.params',
23+
)]
24+
public function __construct(array $config)
25+
{
26+
if (array_key_exists('table_prefix', $config) && is_string($config['table_prefix'])) {
27+
$this->prefix = $config['table_prefix'];
28+
}
29+
}
30+
31+
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void
32+
{
33+
if ($this->prefix === '') {
34+
return;
35+
}
36+
37+
$classMetadata = $eventArgs->getClassMetadata();
38+
if (
39+
! $classMetadata->isInheritanceTypeSingleTable()
40+
|| $classMetadata->getName() === $classMetadata->rootEntityName
41+
) {
42+
$classMetadata->setPrimaryTable([
43+
'name' => $this->prefix . $classMetadata->getTableName(),
44+
]);
45+
}
46+
47+
foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
48+
if ($mapping['type'] === ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) {
49+
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] =
50+
$this->prefix . $mapping['joinTable']['name'];
51+
}
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)