Skip to content

Commit

Permalink
Initial testing
Browse files Browse the repository at this point in the history
  • Loading branch information
bigfoot90 committed Mar 24, 2024
1 parent ccdb800 commit 9ed2a3e
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 37 deletions.
3 changes: 3 additions & 0 deletions src/Schema/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Column extends AbstractAsset

protected ?int $_length = null;

/** @var string[] */
protected array $_members = [];

protected ?int $_precision = null;
Expand Down Expand Up @@ -221,11 +222,13 @@ public function setAutoincrement(bool $flag): self
return $this;
}

/** @return string[] */
public function getMembers(): array
{
return $this->_members;
}

/** @param string[] $members */
public function setMembers(array $members): void
{
$this->_members = $members;
Expand Down
1 change: 1 addition & 0 deletions src/Schema/MySQLSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use function implode;
use function is_string;
use function preg_match;
use function preg_match_all;
use function str_contains;
use function strtok;
use function strtolower;
Expand Down
98 changes: 61 additions & 37 deletions src/Types/EnumType.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,100 +10,124 @@
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Types\Exception\InvalidType;
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
use ReflectionClass;
use Throwable;

use function array_map;
use function class_exists;
use function enum_exists;
use function implode;
use function is_string;
use function sprintf;

final class EnumType extends Type
{
public string $name = 'enum';

public ?string $enumClassname = null;

/** @var array<int, string> */
public array $members = [];

/**
* Gets an array of database types that map to this Doctrine type.
*
* @return string[]
* {@inheritDoc}
*/
public function getMappedDatabaseTypes(AbstractPlatform $platform): array
{
return [$this->name];
}

/**
* Gets the SQL declaration snippet for a field of this type.
*
* @param mixed[] $column The field declaration
* @param AbstractPlatform $platform The currently used database platform
* {@inheritDoc}
*/
public function getSqlDeclaration(array $column, AbstractPlatform $platform): string

Check failure on line 43 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Method Doctrine\DBAL\Types\EnumType::getSqlDeclaration() does not match parent method name: Doctrine\DBAL\Types\Type::getSQLDeclaration().
{
assert($column['type'] instanceof self::class);

$values = implode(
', ',
array_map(
static fn (string $value) => "'{$value}'",
$column['members'] ?: $column['type']->members
)
static fn (string $value) => sprintf('\'%s\'', $value),
$column['members'] ?: $column['type']->members,

Check failure on line 49 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Short ternary operator is not allowed. Use null coalesce operator if applicable or consider using long ternary.
),
);

$sqlDeclaration = match (true) {
return match (true) {
$platform instanceof SqlitePlatform => sprintf('TEXT CHECK(%s IN (%s))', $column['name'], $values),

Check failure on line 54 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

InvalidClass

src/Types/EnumType.php:54:34: InvalidClass: Class, interface or enum Doctrine\DBAL\Platforms\SqlitePlatform has wrong casing (see https://psalm.dev/007)

Check failure on line 54 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Class Doctrine\DBAL\Platforms\SQLitePlatform referenced with incorrect case: Doctrine\DBAL\Platforms\SqlitePlatform.
$platform instanceof PostgreSqlPlatform, $platform instanceof SQLServerPlatform => sprintf('VARCHAR(255) CHECK(%s IN (%s))', $column['name'], $values),

Check warning on line 55 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Line exceeds 120 characters; contains 163 characters

Check failure on line 55 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

InvalidClass

src/Types/EnumType.php:55:34: InvalidClass: Class, interface or enum Doctrine\DBAL\Platforms\PostgreSqlPlatform has wrong casing (see https://psalm.dev/007)

Check failure on line 55 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Class Doctrine\DBAL\Platforms\PostgreSQLPlatform referenced with incorrect case: Doctrine\DBAL\Platforms\PostgreSqlPlatform.
default => sprintf('ENUM(%s)', $values),
};

return $sqlDeclaration;
}

/**
* {@inheritdoc}
*
* @return mixed the database representation of the value
*
* @throws \InvalidArgumentException
* {@inheritDoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if (null === $value) {
if ($value === null) {
return null;
}

if ($value instanceof \UnitEnum) {

Check failure on line 69 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Class \UnitEnum should not be referenced via a fully qualified name, but via a use statement.
return $value->value;

Check failure on line 70 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Access to an undefined property UnitEnum::$value.
}

return (string) $value;
}

/**

Check failure on line 76 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Useless documentation comment with @inheritdoc.
* {@inheritdoc}
*
* @return mixed the PHP representation of the value
* {@inheritDoc}
*/
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed
{
if (null === $value) {
if ($value === null) {
return null;
}

if (!\is_string($value)) {
if (! is_string($value)) {
throw InvalidType::new($value, $this->name, ['null', 'string']);

Check warning on line 86 in src/Types/EnumType.php

View check run for this annotation

Codecov / codecov/patch

src/Types/EnumType.php#L86

Added line #L86 was not covered by tests
}

$refl = new \ReflectionClass($this->enumClassname);

try {
return $refl->newInstance($value);
} catch (\Throwable $e) {
throw ValueNotConvertible::new($value, $this->name, $e->getMessage(), $e);
if ($this->enumClassname) {

Check failure on line 89 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

RiskyTruthyFalsyComparison

src/Types/EnumType.php:89:13: RiskyTruthyFalsyComparison: Operand of type null|string contains type string, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)

Check failure on line 89 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Only booleans are allowed in an if condition, string|null given.
if (enum_exists($this->enumClassname)) {
try {
//var_dump($this->enumClassname::cases());die();
/*$refl = new \ReflectionEnum($this->enumClassname);
foreach ($refl->getCases() as $case) {
if ($value === $case->getValue()->value) {
return $case->getValue();
}
}*/

foreach ($this->enumClassname::cases() as $case) {
if ($value === $case->value) {

Check failure on line 101 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Access to an undefined property UnitEnum::$value.
return $case;
}
}

throw new \ValueError(sprintf("'%s' is not a valid backing value for enum %s", $value, $this->enumClassname));

Check failure on line 106 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Class \ValueError should not be referenced via a fully qualified name, but via a use statement.

Check warning on line 106 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Line exceeds 120 characters; contains 130 characters
} catch (Throwable $e) {
throw ValueNotConvertible::new($value, $this->name, $e->getMessage(), $e);

Check warning on line 108 in src/Types/EnumType.php

View check run for this annotation

Codecov / codecov/patch

src/Types/EnumType.php#L106-L108

Added lines #L106 - L108 were not covered by tests
}
}

if (class_exists($this->enumClassname)) {
$refl = new ReflectionClass($this->enumClassname);

try {
return $refl->newInstance($value);
} catch (Throwable $e) {
throw ValueNotConvertible::new($value, $this->name, $e->getMessage(), $e);

Check warning on line 118 in src/Types/EnumType.php

View check run for this annotation

Codecov / codecov/patch

src/Types/EnumType.php#L117-L118

Added lines #L117 - L118 were not covered by tests
}
}
}

return $value;
}

/**
* {@inheritdoc}
*/
public static function addType(string $name, string $enumClassname): void

Check failure on line 126 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

ParamNameMismatch

src/Types/EnumType.php:126:57: ParamNameMismatch: Argument 2 of Doctrine\DBAL\Types\EnumType::addType has wrong name $enumClassname, expecting $className as defined by Doctrine\DBAL\Types\Type::addType (see https://psalm.dev/230)

Check warning on line 126 in src/Types/EnumType.php

View check run for this annotation

Codecov / codecov/patch

src/Types/EnumType.php#L126

Added line #L126 was not covered by tests
{
self::getTypeRegistry()->register($name, $me = new self());
$me->name = $name;
$me->name = $name;
$me->enumClassname = $enumClassname;
$me->members = $enumClassname::getAllowedValues();
$me->members = $enumClassname::getAllowedValues();

Check failure on line 131 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

UndefinedMethod

src/Types/EnumType.php:131:30: UndefinedMethod: Method Doctrine\DBAL\Types\Type::getallowedvalues does not exist (see https://psalm.dev/022)

Check failure on line 131 in src/Types/EnumType.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (8.3)

Call to an undefined static method Doctrine\DBAL\Types\Type::getAllowedValues().

Check warning on line 131 in src/Types/EnumType.php

View check run for this annotation

Codecov / codecov/patch

src/Types/EnumType.php#L128-L131

Added lines #L128 - L131 were not covered by tests
}
}
32 changes: 32 additions & 0 deletions tests/Functional/Types/EnumTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Tests\Functional\Types;

use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Tests\FunctionalTestCase;
use Doctrine\DBAL\Types\Types;

class EnumTest extends FunctionalTestCase
{
protected function setUp(): void
{
$table = new Table('enum_table');
$table->addColumn('val', Types::ENUM, ['members' => ['a', 'b']]);

$this->dropAndCreateTable($table);
}

public function testInsertAndSelect(): void
{
$val = 'b';

$result = $this->connection->insert('enum_table', ['val' => $val]);
self::assertSame(1, $result);

$value = $this->connection->fetchOne('SELECT val FROM enum_table');

self::assertEquals($val, $value);
}
}
14 changes: 14 additions & 0 deletions tests/Schema/ColumnTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function testToArray(): void
'default' => 'baz',
'notnull' => false,
'length' => 200,
'members' => [],
'precision' => 5,
'scale' => 2,
'fixed' => true,
Expand Down Expand Up @@ -148,4 +149,17 @@ public function testColumnComment(): void
self::assertArrayHasKey('comment', $columnArray);
self::assertEquals('foo', $columnArray['comment']);
}

public function testEnumMembers(): void
{
$column = new Column('bar', Type::getType(Types::ENUM));
self::assertSame([], $column->getMembers());

$column->setMembers(['a', 'b']);
self::assertEquals(['a', 'b'], $column->getMembers());

$columnArray = $column->toArray();
self::assertArrayHasKey('members', $columnArray);
self::assertEquals(['a', 'b'], $columnArray['members']);
}
}
95 changes: 95 additions & 0 deletions tests/Types/EnumTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

Check warning on line 1 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute logic with side effects, but should not do both. The first symbol is defined on line 14 and the first side effect is on line 95.

declare(strict_types=1);

namespace Doctrine\DBAL\Tests\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\EnumType;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

use function anonymous_class;

Check failure on line 12 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Type anonymous_class is not used in this file.

class EnumTest extends TestCase
{
private AbstractPlatform&MockObject $platform;
private EnumType $type;

protected function setUp(): void
{
$this->platform = $this->createMock(AbstractPlatform::class);
$this->type = new EnumType();

Check failure on line 22 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Equals sign not aligned with surrounding assignments; expected 5 spaces but found 1 space
}

public function testReturnsSQLDeclaration(): void
{
self::assertSame('ENUM(\'a\', \'b\')', $this->type->getSQLDeclaration(['members' => ['a', 'b']], $this->platform));

Check warning on line 27 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Line exceeds 120 characters; contains 123 characters
}

public function testConvertToPHPValue(): void
{
self::assertIsString($this->type->convertToPHPValue('foo', $this->platform));
self::assertIsString($this->type->convertToPHPValue('', $this->platform));
self::assertNull($this->type->convertToPHPValue(null, $this->platform));
}

public function testConvertToPHPEnum(): void
{
$this->type->enumClassname = EnumPhp::class;

self::assertInstanceOf($this->type->enumClassname, $this->type->convertToPHPValue('a', $this->platform));
self::assertSame(EnumPhp::VALUE_A, $this->type->convertToPHPValue('a', $this->platform));
self::assertNull($this->type->convertToPHPValue(null, $this->platform));
}

public function testConvertToPHPObject(): void
{
$this->type->enumClassname = EnumClass::class;

self::assertInstanceOf($this->type->enumClassname, $this->type->convertToPHPValue('a', $this->platform));
self::assertEquals(new EnumClass('a'), $this->type->convertToPHPValue('a', $this->platform));
self::assertNull($this->type->convertToPHPValue(null, $this->platform));
}

public function testConvertStringToDatabaseValue(): void
{
self::assertSame('a', $this->type->convertToDatabaseValue('a', $this->platform));
self::assertNull($this->type->convertToDatabaseValue(null, $this->platform));
}

public function testConvertEnumToDatabaseValue(): void
{
$this->type->enumClassname = EnumPhp::class;

self::assertSame('a', $this->type->convertToDatabaseValue(EnumPhp::VALUE_A, $this->platform));
self::assertNull($this->type->convertToDatabaseValue(null, $this->platform));
}

public function testConvertObjectToDatabaseValue(): void
{
$enum = new EnumClass('a');

Check failure on line 71 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Equals sign not aligned with surrounding assignments; expected 22 spaces but found 1 space
$this->type->enumClassname = EnumClass::class;

self::assertSame('a', $this->type->convertToDatabaseValue($enum, $this->platform));
self::assertNull($this->type->convertToDatabaseValue(null, $this->platform));
}
}

enum EnumPhp: string
{
case VALUE_A = 'a';
case VALUE_B = 'b';
}

final class EnumClass implements \Stringable {

Check failure on line 85 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Class \Stringable should not be referenced via a fully qualified name, but via a use statement.

Check failure on line 85 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Opening brace of a class must be on the line after the definition
function __construct(

Check failure on line 86 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Coding Standards / Coding Standards (8.3)

Visibility must be declared on method "__construct"
private ?string $value
) {
}

function __tostring(): string

Check failure on line 91 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

InvalidToString

tests/Types/EnumTest.php:91:28: InvalidToString: __toString methods must return a string, null|string returned (see https://psalm.dev/055)
{
return $this->value;

Check failure on line 93 in tests/Types/EnumTest.php

View workflow job for this annotation

GitHub Actions / Static Analysis with Psalm (8.3)

NullableReturnStatement

tests/Types/EnumTest.php:93:16: NullableReturnStatement: The declared return type 'string' for Doctrine\DBAL\Tests\Types\EnumClass::__tostring is not nullable, but the function returns 'null|string' (see https://psalm.dev/139)
}
};

0 comments on commit 9ed2a3e

Please sign in to comment.