Skip to content

Commit eb5ec6e

Browse files
author
Pavel Batanov
authored
Merge pull request #1 from lamoda/fix-type-mapping-and-sql-declaration
Fix doctrine type mapping and sql declaration
2 parents c06de58 + c226679 commit eb5ec6e

File tree

10 files changed

+242
-5
lines changed

10 files changed

+242
-5
lines changed

src/DBAL/EnumType.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,20 @@
1212

1313
final class EnumType extends Type
1414
{
15+
private const MAPPED_TYPE_STRING = 'string';
16+
1517
/** @var string */
1618
private $fqcn;
19+
1720
/** @var string */
1821
private $name;
22+
1923
/** @var NamingStrategyInterface */
2024
private $strategy;
2125

26+
/** @var bool */
27+
private $enumNameTypeMapping = false;
28+
2229
public function setName(string $name): void
2330
{
2431
$this->name = $name;
@@ -43,6 +50,16 @@ private function getStrategy(): NamingStrategyInterface
4350
return $this->strategy;
4451
}
4552

53+
public function setEnumNameTypeMapping(bool $enumNameTypeMapping): void
54+
{
55+
$this->enumNameTypeMapping = $enumNameTypeMapping;
56+
}
57+
58+
public function isEnumNameTypeMapping(): bool
59+
{
60+
return $this->enumNameTypeMapping;
61+
}
62+
4663
/**
4764
* {@inheritdoc}
4865
*/
@@ -81,6 +98,10 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform)
8198
/** {@inheritdoc} */
8299
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
83100
{
101+
if ($this->isEnumNameTypeMapping() === true) {
102+
return $this->getName();
103+
}
104+
84105
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
85106
}
86107

@@ -89,4 +110,13 @@ public function getName(): string
89110
{
90111
return $this->name;
91112
}
113+
114+
public function getMappedDatabaseTypes(AbstractPlatform $platform)
115+
{
116+
if ($this->isEnumNameTypeMapping() === true) {
117+
return [$this->name => $this->name];
118+
}
119+
120+
return [$this->name => self::MAPPED_TYPE_STRING];
121+
}
92122
}

src/DBAL/EnumTypeInitializer.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,29 @@ final class EnumTypeInitializer
1111
* @param string $type
1212
* @param string $fqcn
1313
* @param NamingStrategyInterface|null $strategy
14+
* @param bool $enumNameTypeMapping
1415
*
1516
* @throws \Doctrine\DBAL\DBALException
1617
*/
17-
public function initialize(string $type, string $fqcn, NamingStrategyInterface $strategy = null): void
18-
{
18+
public function initialize(
19+
string $type,
20+
string $fqcn,
21+
NamingStrategyInterface $strategy = null,
22+
bool $enumNameTypeMapping = false
23+
): void {
1924
if (Type::hasType($type)) {
2025
return;
2126
}
2227

2328
Type::addType($type, EnumType::class);
29+
2430
/** @var EnumType $typeInstance */
2531
$typeInstance = Type::getType($type);
2632
$typeInstance->setFqcn($fqcn);
2733
$typeInstance->setName($type);
2834
if ($strategy) {
2935
$typeInstance->setStrategy($strategy);
3036
}
37+
$typeInstance->setEnumNameTypeMapping($enumNameTypeMapping);
3138
}
3239
}

src/DependencyInjection/Configuration.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public function getConfigTreeBuilder(): TreeBuilder
1515

1616
$root = $builder->root('lamoda_enum');
1717

18+
$root->children()->booleanNode('enum_name_type_mapping')
19+
->defaultValue(false);
20+
1821
$this->configureEnumNodes($root);
1922

2023
return $builder;

src/DependencyInjection/LamodaEnumExtension.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Lamoda\EnumBundle\DependencyInjection;
44

5+
use Doctrine\ORM\EntityManager;
56
use Lamoda\EnumBundle\DBAL\EnumTypeInitializer;
67
use Lamoda\EnumBundle\Naming\IdenticalNamingStrategy;
78
use Lamoda\EnumBundle\Naming\LowercaseNamingStrategy;
@@ -25,7 +26,7 @@ public function load(array $configs, ContainerBuilder $container): void
2526
foreach ($configs['dbal_types'] ?? [] as $name => $typeConfig) {
2627
$fqcn = $typeConfig['class'];
2728
$strategy = $this->getStrategy($typeConfig['strategy'] ?? null);
28-
$typeInitializer->addMethodCall('initialize', [$name, $fqcn, $strategy]);
29+
$typeInitializer->addMethodCall('initialize', [$name, $fqcn, $strategy, $configs['enum_name_type_mapping']]);
2930
}
3031
}
3132

tests/Functional/Fixtures/TestKernel.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88

99
final class TestKernel extends Kernel
1010
{
11+
/** @var string */
12+
private $configFileName = 'config.yml';
13+
14+
/** @var string */
15+
private $cacheDirPostfix = '';
16+
1117
/** {@inheritdoc} */
1218
public function registerBundles()
1319
{
@@ -18,16 +24,42 @@ public function registerBundles()
1824

1925
public function registerContainerConfiguration(LoaderInterface $loader)
2026
{
21-
$loader->load(__DIR__ . '/config.yml');
27+
$loader->load(__DIR__.'/'.$this->getConfigFileName());
2228
}
2329

2430
public function getCacheDir()
2531
{
26-
return __DIR__.'/../../../build/cache';
32+
return __DIR__.'/../../../build/cache'.$this->getCacheDirPostfix();
2733
}
2834

2935
public function getLogDir()
3036
{
3137
return __DIR__.'/../../../build/logs';
3238
}
39+
40+
/**
41+
* @return string
42+
*/
43+
public function getConfigFileName(): string
44+
{
45+
return $this->configFileName;
46+
}
47+
48+
/**
49+
* @param string $configFileName
50+
*/
51+
public function setConfigFileName(string $configFileName): void
52+
{
53+
$this->configFileName = $configFileName;
54+
}
55+
56+
public function getCacheDirPostfix(): string
57+
{
58+
return $this->cacheDirPostfix;
59+
}
60+
61+
public function setCacheDirPostfix(string $cacheDirPostfix): void
62+
{
63+
$this->cacheDirPostfix = $cacheDirPostfix;
64+
}
3365
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
lamoda_enum:
2+
enum_name_type_mapping: true
3+
dbal_types:
4+
test_enum: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
5+
test_enum_extended:
6+
class: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
7+
strategy: lowercase
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
lamoda_enum:
2+
enum_name_type_mapping: false
3+
dbal_types:
4+
test_enum: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
5+
test_enum_extended:
6+
class: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
7+
strategy: lowercase
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
namespace Lamoda\EnumBundle\Tests\Functional;
4+
5+
use Doctrine\DBAL\Platforms\AbstractPlatform;
6+
use Doctrine\DBAL\Types\Type;
7+
use Lamoda\EnumBundle\DBAL\EnumType;
8+
use Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum;
9+
use Lamoda\EnumBundle\Tests\Functional\Fixtures\TestKernel;
10+
use PHPUnit\Framework\TestCase;
11+
use Symfony\Component\HttpKernel\Kernel;
12+
13+
final class TestCustomTypeMapping extends TestCase
14+
{
15+
protected function setUp(): void
16+
{
17+
$typeReflectionClass = new \ReflectionClass(Type::class);
18+
19+
$typesMapProperty = $typeReflectionClass->getProperty('_typesMap');
20+
$typesMapProperty->setAccessible(true);
21+
$typesMapProperty->setValue([]);
22+
}
23+
24+
/**
25+
* @param string $configFileName
26+
* @param string $expectedTestEnumSqlDeclaration
27+
* @param string $expectedTestEnumExtendedSqlDeclaration
28+
* @param array $expectedTestEnumMappedTypes
29+
* @param array $expectedTestEnumExtendedMappedTypes
30+
*
31+
* @throws \Doctrine\DBAL\DBALException
32+
*
33+
* @dataProvider dataTypeMapping
34+
*/
35+
public function testTypeMapping(
36+
string $configFileName,
37+
string $expectedTestEnumSqlDeclaration,
38+
string $expectedTestEnumExtendedSqlDeclaration,
39+
array $expectedTestEnumMappedTypes,
40+
array $expectedTestEnumExtendedMappedTypes
41+
): void {
42+
$kernel = $this->createKernel($configFileName);
43+
44+
$basic = Type::getType('test_enum');
45+
$extended = Type::getType('test_enum_extended');
46+
47+
$platform = $this->createMock(AbstractPlatform::class);
48+
$platform->method('getVarcharTypeDeclarationSQL')
49+
->willReturn('VARCHAR(255)');
50+
51+
self::assertSame($expectedTestEnumSqlDeclaration, $basic->getSQLDeclaration([], $platform));
52+
self::assertSame($expectedTestEnumExtendedSqlDeclaration, $extended->getSQLDeclaration([], $platform));
53+
54+
self::assertSame($expectedTestEnumMappedTypes, $basic->getMappedDatabaseTypes($platform));
55+
self::assertSame($expectedTestEnumExtendedMappedTypes, $extended->getMappedDatabaseTypes($platform));
56+
57+
$kernel->shutdown();
58+
}
59+
60+
public function dataTypeMapping(): array
61+
{
62+
return [
63+
[
64+
'config.yml',
65+
'VARCHAR(255)',
66+
'VARCHAR(255)',
67+
['test_enum' => 'string'],
68+
['test_enum_extended' => 'string'],
69+
],
70+
[
71+
'config_type_mapping.yml',
72+
'test_enum',
73+
'test_enum_extended',
74+
['test_enum' => 'test_enum'],
75+
['test_enum_extended' => 'test_enum_extended'],
76+
],
77+
[
78+
'config_type_mapping_false.yml',
79+
'VARCHAR(255)',
80+
'VARCHAR(255)',
81+
['test_enum' => 'string'],
82+
['test_enum_extended' => 'string'],
83+
],
84+
];
85+
}
86+
87+
private function createKernel(string $configFileName): Kernel
88+
{
89+
$kernel = new TestKernel('test', true);
90+
$kernel->setConfigFileName($configFileName);
91+
$kernel->setCacheDirPostfix(sha1($configFileName));
92+
$kernel->boot();
93+
94+
return $kernel;
95+
}
96+
}

tests/Unit/DBAL/EnumTypeInitializerTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ final class EnumTypeInitializerTest extends TestCase
1919
{
2020
private const TESTED_TYPE = 'test_type';
2121

22+
protected function setUp(): void
23+
{
24+
$typeReflectionClass = new \ReflectionClass(Type::class);
25+
26+
$typesMapProperty = $typeReflectionClass->getProperty('_typesMap');
27+
$typesMapProperty->setAccessible(true);
28+
$typesMapProperty->setValue([]);
29+
}
30+
2231
public function testInitializerLoadsType(): void
2332
{
2433
$initalizer = new EnumTypeInitializer();
@@ -33,6 +42,47 @@ public function testInitializerLoadsType(): void
3342
self::assertEquals('ONE', (string) $enum);
3443
}
3544

45+
/**
46+
* @param bool $enumNameTypeMapping
47+
* @param string $expectedType
48+
* @param array $expectedMappedTypes
49+
*
50+
* @throws \Doctrine\DBAL\DBALException
51+
*
52+
* @dataProvider dataInitializerLoadsTypeWithMappingFlag
53+
*/
54+
public function testInitializerLoadsTypeWithMappingFlag(
55+
bool $enumNameTypeMapping,
56+
string $expectedType,
57+
array $expectedMappedTypes
58+
): void {
59+
$initalizer = new EnumTypeInitializer();
60+
$initalizer->initialize(
61+
self::TESTED_TYPE,
62+
TestEnum::class,
63+
new IdenticalNamingStrategy(),
64+
$enumNameTypeMapping
65+
);
66+
67+
$platform = $this->createMock(AbstractPlatform::class);
68+
$platform->method('getVarcharTypeDeclarationSQL')
69+
->willReturn('VARCHAR(255)');
70+
71+
$type = Type::getType(self::TESTED_TYPE);
72+
73+
self::assertEquals($enumNameTypeMapping, $type->isEnumNameTypeMapping());
74+
self::assertEquals($expectedType, $type->getSQLDeclaration([], $platform));
75+
self::assertEquals($expectedMappedTypes, $type->getMappedDatabaseTypes($platform));
76+
}
77+
78+
public function dataInitializerLoadsTypeWithMappingFlag()
79+
{
80+
return [
81+
[false, 'VARCHAR(255)', [self::TESTED_TYPE => 'string']],
82+
[true, self::TESTED_TYPE, [self::TESTED_TYPE => self::TESTED_TYPE]]
83+
];
84+
}
85+
3686
/**
3787
* @runInSeparateProcess
3888
*/

tests/Unit/DependencyInjection/LamodaEnumExtensionTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public function testExtensionLoadsFilledConfigs(): void
3838
$extension->load(
3939
[
4040
[
41+
'enum_name_type_mapping' => true,
4142
'dbal_types' => [
4243
'type_1' => TestEnum::class,
4344
'type_2' => [
@@ -52,10 +53,12 @@ public function testExtensionLoadsFilledConfigs(): void
5253

5354
$initDef = $builder->getDefinition(EnumTypeInitializer::class);
5455
$calls = $initDef->getMethodCalls();
56+
5557
self::assertCount(2, $calls);
5658
self::assertSame('initialize', $calls[0][0]);
5759
self::assertSame('type_1', $calls[0][1][0]);
5860
self::assertSame(TestEnum::class, $calls[0][1][1]);
61+
self::assertSame(true, $calls[0][1][3]);
5962
/** @var Reference $strat1 */
6063
$strat1 = $calls[0][1][2];
6164
self::assertInstanceOf(Reference::class, $strat1);
@@ -64,6 +67,7 @@ public function testExtensionLoadsFilledConfigs(): void
6467
self::assertSame('initialize', $calls[1][0]);
6568
self::assertSame('type_2', $calls[1][1][0]);
6669
self::assertSame(TestEnum::class, $calls[1][1][1]);
70+
self::assertSame(true, $calls[1][1][3]);
6771
/** @var Reference $strat1 */
6872
$strat1 = $calls[1][1][2];
6973
self::assertInstanceOf(Reference::class, $strat1);

0 commit comments

Comments
 (0)