Skip to content

Fix doctrine type mapping and sql declaration #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/DBAL/EnumType.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@

final class EnumType extends Type
{
private const MAPPED_TYPE_STRING = 'string';

/** @var string */
private $fqcn;

/** @var string */
private $name;

/** @var NamingStrategyInterface */
private $strategy;

/** @var bool */
private $enumNameTypeMapping = false;

public function setName(string $name): void
{
$this->name = $name;
Expand All @@ -43,6 +50,16 @@ private function getStrategy(): NamingStrategyInterface
return $this->strategy;
}

public function setEnumNameTypeMapping(bool $enumNameTypeMapping): void
{
$this->enumNameTypeMapping = $enumNameTypeMapping;
}

public function isEnumNameTypeMapping(): bool
{
return $this->enumNameTypeMapping;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -81,6 +98,10 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform)
/** {@inheritdoc} */
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
if ($this->isEnumNameTypeMapping() === true) {
return $this->getName();
}

return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
}

Expand All @@ -89,4 +110,13 @@ public function getName(): string
{
return $this->name;
}

public function getMappedDatabaseTypes(AbstractPlatform $platform)
{
if ($this->isEnumNameTypeMapping() === true) {
return [$this->name => $this->name];
}

return [$this->name => self::MAPPED_TYPE_STRING];
}
}
11 changes: 9 additions & 2 deletions src/DBAL/EnumTypeInitializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,29 @@ final class EnumTypeInitializer
* @param string $type
* @param string $fqcn
* @param NamingStrategyInterface|null $strategy
* @param bool $enumNameTypeMapping
*
* @throws \Doctrine\DBAL\DBALException
*/
public function initialize(string $type, string $fqcn, NamingStrategyInterface $strategy = null): void
{
public function initialize(
string $type,
string $fqcn,
NamingStrategyInterface $strategy = null,
bool $enumNameTypeMapping = false
): void {
if (Type::hasType($type)) {
return;
}

Type::addType($type, EnumType::class);

/** @var EnumType $typeInstance */
$typeInstance = Type::getType($type);
$typeInstance->setFqcn($fqcn);
$typeInstance->setName($type);
if ($strategy) {
$typeInstance->setStrategy($strategy);
}
$typeInstance->setEnumNameTypeMapping($enumNameTypeMapping);
}
}
3 changes: 3 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public function getConfigTreeBuilder(): TreeBuilder

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

$root->children()->booleanNode('enum_name_type_mapping')
->defaultValue(false);

$this->configureEnumNodes($root);

return $builder;
Expand Down
3 changes: 2 additions & 1 deletion src/DependencyInjection/LamodaEnumExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Lamoda\EnumBundle\DependencyInjection;

use Doctrine\ORM\EntityManager;
use Lamoda\EnumBundle\DBAL\EnumTypeInitializer;
use Lamoda\EnumBundle\Naming\IdenticalNamingStrategy;
use Lamoda\EnumBundle\Naming\LowercaseNamingStrategy;
Expand All @@ -25,7 +26,7 @@ public function load(array $configs, ContainerBuilder $container): void
foreach ($configs['dbal_types'] ?? [] as $name => $typeConfig) {
$fqcn = $typeConfig['class'];
$strategy = $this->getStrategy($typeConfig['strategy'] ?? null);
$typeInitializer->addMethodCall('initialize', [$name, $fqcn, $strategy]);
$typeInitializer->addMethodCall('initialize', [$name, $fqcn, $strategy, $configs['enum_name_type_mapping']]);
}
}

Expand Down
36 changes: 34 additions & 2 deletions tests/Functional/Fixtures/TestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

final class TestKernel extends Kernel
{
/** @var string */
private $configFileName = 'config.yml';

/** @var string */
private $cacheDirPostfix = '';

/** {@inheritdoc} */
public function registerBundles()
{
Expand All @@ -18,16 +24,42 @@ public function registerBundles()

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__ . '/config.yml');
$loader->load(__DIR__.'/'.$this->getConfigFileName());
}

public function getCacheDir()
{
return __DIR__.'/../../../build/cache';
return __DIR__.'/../../../build/cache'.$this->getCacheDirPostfix();
}

public function getLogDir()
{
return __DIR__.'/../../../build/logs';
}

/**
* @return string
*/
public function getConfigFileName(): string
{
return $this->configFileName;
}

/**
* @param string $configFileName
*/
public function setConfigFileName(string $configFileName): void
{
$this->configFileName = $configFileName;
}

public function getCacheDirPostfix(): string
{
return $this->cacheDirPostfix;
}

public function setCacheDirPostfix(string $cacheDirPostfix): void
{
$this->cacheDirPostfix = $cacheDirPostfix;
}
}
7 changes: 7 additions & 0 deletions tests/Functional/Fixtures/config_type_mapping.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lamoda_enum:
enum_name_type_mapping: true
dbal_types:
test_enum: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
test_enum_extended:
class: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
strategy: lowercase
7 changes: 7 additions & 0 deletions tests/Functional/Fixtures/config_type_mapping_false.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lamoda_enum:
enum_name_type_mapping: false
dbal_types:
test_enum: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
test_enum_extended:
class: Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum
strategy: lowercase
96 changes: 96 additions & 0 deletions tests/Functional/TestCustomTypeMapping.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace Lamoda\EnumBundle\Tests\Functional;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
use Lamoda\EnumBundle\DBAL\EnumType;
use Lamoda\EnumBundle\Tests\Functional\Fixtures\TestEnum;
use Lamoda\EnumBundle\Tests\Functional\Fixtures\TestKernel;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Kernel;

final class TestCustomTypeMapping extends TestCase
{
protected function setUp(): void
{
$typeReflectionClass = new \ReflectionClass(Type::class);

$typesMapProperty = $typeReflectionClass->getProperty('_typesMap');
$typesMapProperty->setAccessible(true);
$typesMapProperty->setValue([]);
}

/**
* @param string $configFileName
* @param string $expectedTestEnumSqlDeclaration
* @param string $expectedTestEnumExtendedSqlDeclaration
* @param array $expectedTestEnumMappedTypes
* @param array $expectedTestEnumExtendedMappedTypes
*
* @throws \Doctrine\DBAL\DBALException
*
* @dataProvider dataTypeMapping
*/
public function testTypeMapping(
string $configFileName,
string $expectedTestEnumSqlDeclaration,
string $expectedTestEnumExtendedSqlDeclaration,
array $expectedTestEnumMappedTypes,
array $expectedTestEnumExtendedMappedTypes
): void {
$kernel = $this->createKernel($configFileName);

$basic = Type::getType('test_enum');
$extended = Type::getType('test_enum_extended');

$platform = $this->createMock(AbstractPlatform::class);
$platform->method('getVarcharTypeDeclarationSQL')
->willReturn('VARCHAR(255)');

self::assertSame($expectedTestEnumSqlDeclaration, $basic->getSQLDeclaration([], $platform));
self::assertSame($expectedTestEnumExtendedSqlDeclaration, $extended->getSQLDeclaration([], $platform));

self::assertSame($expectedTestEnumMappedTypes, $basic->getMappedDatabaseTypes($platform));
self::assertSame($expectedTestEnumExtendedMappedTypes, $extended->getMappedDatabaseTypes($platform));

$kernel->shutdown();
}

public function dataTypeMapping(): array
{
return [
[
'config.yml',
'VARCHAR(255)',
'VARCHAR(255)',
['test_enum' => 'string'],
['test_enum_extended' => 'string'],
],
[
'config_type_mapping.yml',
'test_enum',
'test_enum_extended',
['test_enum' => 'test_enum'],
['test_enum_extended' => 'test_enum_extended'],
],
[
'config_type_mapping_false.yml',
'VARCHAR(255)',
'VARCHAR(255)',
['test_enum' => 'string'],
['test_enum_extended' => 'string'],
],
];
}

private function createKernel(string $configFileName): Kernel
{
$kernel = new TestKernel('test', true);
$kernel->setConfigFileName($configFileName);
$kernel->setCacheDirPostfix(sha1($configFileName));
$kernel->boot();

return $kernel;
}
}
50 changes: 50 additions & 0 deletions tests/Unit/DBAL/EnumTypeInitializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ final class EnumTypeInitializerTest extends TestCase
{
private const TESTED_TYPE = 'test_type';

protected function setUp(): void
{
$typeReflectionClass = new \ReflectionClass(Type::class);

$typesMapProperty = $typeReflectionClass->getProperty('_typesMap');
$typesMapProperty->setAccessible(true);
$typesMapProperty->setValue([]);
}

public function testInitializerLoadsType(): void
{
$initalizer = new EnumTypeInitializer();
Expand All @@ -33,6 +42,47 @@ public function testInitializerLoadsType(): void
self::assertEquals('ONE', (string) $enum);
}

/**
* @param bool $enumNameTypeMapping
* @param string $expectedType
* @param array $expectedMappedTypes
*
* @throws \Doctrine\DBAL\DBALException
*
* @dataProvider dataInitializerLoadsTypeWithMappingFlag
*/
public function testInitializerLoadsTypeWithMappingFlag(
bool $enumNameTypeMapping,
string $expectedType,
array $expectedMappedTypes
): void {
$initalizer = new EnumTypeInitializer();
$initalizer->initialize(
self::TESTED_TYPE,
TestEnum::class,
new IdenticalNamingStrategy(),
$enumNameTypeMapping
);

$platform = $this->createMock(AbstractPlatform::class);
$platform->method('getVarcharTypeDeclarationSQL')
->willReturn('VARCHAR(255)');

$type = Type::getType(self::TESTED_TYPE);

self::assertEquals($enumNameTypeMapping, $type->isEnumNameTypeMapping());
self::assertEquals($expectedType, $type->getSQLDeclaration([], $platform));
self::assertEquals($expectedMappedTypes, $type->getMappedDatabaseTypes($platform));
}

public function dataInitializerLoadsTypeWithMappingFlag()
{
return [
[false, 'VARCHAR(255)', [self::TESTED_TYPE => 'string']],
[true, self::TESTED_TYPE, [self::TESTED_TYPE => self::TESTED_TYPE]]
];
}

/**
* @runInSeparateProcess
*/
Expand Down
4 changes: 4 additions & 0 deletions tests/Unit/DependencyInjection/LamodaEnumExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function testExtensionLoadsFilledConfigs(): void
$extension->load(
[
[
'enum_name_type_mapping' => true,
'dbal_types' => [
'type_1' => TestEnum::class,
'type_2' => [
Expand All @@ -52,10 +53,12 @@ public function testExtensionLoadsFilledConfigs(): void

$initDef = $builder->getDefinition(EnumTypeInitializer::class);
$calls = $initDef->getMethodCalls();

self::assertCount(2, $calls);
self::assertSame('initialize', $calls[0][0]);
self::assertSame('type_1', $calls[0][1][0]);
self::assertSame(TestEnum::class, $calls[0][1][1]);
self::assertSame(true, $calls[0][1][3]);
/** @var Reference $strat1 */
$strat1 = $calls[0][1][2];
self::assertInstanceOf(Reference::class, $strat1);
Expand All @@ -64,6 +67,7 @@ public function testExtensionLoadsFilledConfigs(): void
self::assertSame('initialize', $calls[1][0]);
self::assertSame('type_2', $calls[1][1][0]);
self::assertSame(TestEnum::class, $calls[1][1][1]);
self::assertSame(true, $calls[1][1][3]);
/** @var Reference $strat1 */
$strat1 = $calls[1][1][2];
self::assertInstanceOf(Reference::class, $strat1);
Expand Down