Skip to content
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

Upgrade to Symfony 7.1 + new features #240

Merged
merged 15 commits into from
May 31, 2024
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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ jobs:
- '8.2'
symfony-version:
- '7.0'
- '7.1'
steps:
- name: 'Checkout Code'
uses: actions/checkout@v4
Expand Down Expand Up @@ -152,14 +153,15 @@ jobs:
run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover=coverage.xml

- name: 'Download Coverage Files'
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
path: reports

- name: 'Upload to Codecov'
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
files: ./coverage.xml
fail_ci_if_error: true
flags: unittests
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
25 changes: 17 additions & 8 deletions Command/EnumDropCommentCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@

namespace Fresh\DoctrineEnumBundle\Command;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Fresh\DoctrineEnumBundle\DBAL\Types\AbstractEnumType;
use Fresh\DoctrineEnumBundle\Exception\EnumType\EnumTypeIsRegisteredButClassDoesNotExistException;
use Fresh\DoctrineEnumBundle\Exception\InvalidArgumentException;
use Fresh\DoctrineEnumBundle\Exception\RuntimeException;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -75,6 +73,16 @@ public function __construct(private readonly ManagerRegistry $registry, array $r
}
}

/**
* @return \Closure
*/
public function getEnumTypesForAutocompletion(): \Closure
{
return function () {
return \array_keys($this->registeredEnumTypes);
};
}

/**
* {@inheritdoc}
*/
Expand All @@ -83,7 +91,7 @@ protected function configure(): void
$this
->setDefinition(
new InputDefinition([
new InputArgument('enumType', InputArgument::REQUIRED, 'Registered ENUM type'),
new InputArgument('enumType', InputArgument::REQUIRED, 'Registered ENUM type', null, $this->getEnumTypesForAutocompletion()),
new InputOption('em', null, InputOption::VALUE_OPTIONAL, 'The entity manager to use for this command'),
])
)
Expand Down Expand Up @@ -143,9 +151,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$connection = $this->em->getConnection();

$platform = $connection->getDatabasePlatform();
if (!$platform instanceof AbstractPlatform) {
throw new RuntimeException('Missing database platform for connection.', 3);
}

$io->title(\sprintf('Dropping comments for <info>%s</info> type...', $this->enumType));

Expand All @@ -157,13 +162,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int

foreach ($allMetadata as $metadata) {
$entityName = $metadata->getName();
$tableName = $metadata->getTableName();
if (!empty($metadata->getSchemaName())) {
$tableName = $metadata->getSchemaName().'.'.$metadata->getTableName();
} else {
$tableName = $metadata->getTableName();
}

foreach ($metadata->getFieldNames() as $fieldName) {
if ($metadata->getTypeOfField($fieldName) === $this->enumType) {
/** @var array{columnName: string} $fieldMappingDetails */
$fieldMappingDetails = $metadata->getFieldMapping($fieldName);
$sql = $platform->getCommentOnColumnSQL($tableName, $fieldMappingDetails['columnName'], null);
$sql = $platform->getCommentOnColumnSQL($tableName, $fieldMappingDetails['columnName'], 'NULL');
$connection->executeQuery($sql);

$io->text(\sprintf(' * %s::$%s <info>Dropped ✔</info>', $entityName, $fieldName));
Expand Down
8 changes: 4 additions & 4 deletions DBAL/Types/AbstractEnumType.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Types\Type;
use Fresh\DoctrineEnumBundle\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -51,7 +51,7 @@ abstract class AbstractEnumType extends Type
*
* @return TValue|int|string
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): mixed
{
if (null !== $value && !isset(static::$choices[$value])) {
throw new InvalidArgumentException(\sprintf('Invalid value "%s" for ENUM "%s".', $value, $this->getName()));
Expand All @@ -66,7 +66,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform)
*
* @return TValue
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
public function convertToPHPValue($value, AbstractPlatform $platform): mixed
{
if (!isset(static::$choices[$value])) {
return $value;
Expand Down Expand Up @@ -104,7 +104,7 @@ static function (int|string $value) {
);

$sqlDeclaration = match (true) {
$platform instanceof SqlitePlatform => \sprintf('TEXT CHECK(%s IN (%s))', $column['name'], $values),
$platform instanceof SQLitePlatform => \sprintf('TEXT CHECK(%s IN (%s))', $column['name'], $values),
$platform instanceof PostgreSQLPlatform, $platform instanceof SQLServerPlatform => \sprintf(
'VARCHAR(255) CHECK(%s IN (%s))',
$column['name'],
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@

##### Choose the version you need

| Bundle Version (X.Y.Z) | PHP | Symfony | Doctrine Bundle | Comment |
| Bundle Version (X.Y.Z) | PHP | Symfony | Doctrine Bundle | Comment |
|:----------------------:|:--------:|:----------:|:---------------:|:--------------------|
| `10.1.*` | `>= 8.2` | `>= 7.0` | `>= 2.11` | **Current version** |
| `9.2.*` | `>= 8.1` | `>= 6.1` | `>= 2.9` | Previous version |
| `11.0.*` | `>= 8.2` | `>= 7.0` | `>= 2.11` | **Current version** |
| `10.1.*` | `>= 8.2` | `>= 7.0` | `>= 2.11` | Previous |

#### Check the `config/bundles.php` file

Expand Down
12 changes: 6 additions & 6 deletions Resources/docs/usage_example.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ Register `BasketballPositionType` for Doctrine in config.yaml:

```yaml
doctrine:
dbal:
types:
BasketballPositionType: App\DBAL\Types\BasketballPositionType
dbal:
types:
BasketballPositionType: App\DBAL\Types\BasketballPositionType
```

Create a `Player` entity that has a `position` field:
Expand All @@ -60,9 +60,9 @@ use Fresh\DoctrineEnumBundle\Validator\Constraints as DoctrineAssert;
#[ORM\Table(name: 'players')]
class Player
{
#[ORM\Id]
#[ORM\Column(type: 'integer', name: 'id')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ORM\Id]
#[ORM\Column(type: 'integer', name: 'id')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private $id;

// Note, that type of field should be same as you set in Doctrine config (in this case it is BasketballPositionType)
Expand Down
75 changes: 46 additions & 29 deletions Tests/Command/EnumDropCommentCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
use Fresh\DoctrineEnumBundle\Exception\EnumType\EnumTypeIsRegisteredButClassDoesNotExistException;
use Fresh\DoctrineEnumBundle\Tests\Fixtures\DBAL\Types\BasketballPositionType;
use Fresh\DoctrineEnumBundle\Tests\Fixtures\DBAL\Types\TaskStatusType;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
Expand Down Expand Up @@ -94,7 +96,8 @@ protected function tearDown(): void
);
}

public function testExceptionInConstructor(): void
#[Test]
public function exceptionInConstructor(): void
{
$this->expectException(EnumTypeIsRegisteredButClassDoesNotExistException::class);
$this->expectExceptionMessage('ENUM type "CustomType" is registered as "Fresh\DoctrineEnumBundle\Tests\Fixtures\DBAL\Types\CustomType", but that class does not exist');
Expand All @@ -110,7 +113,8 @@ public function testExceptionInConstructor(): void
$this->commandTester->getDisplay();
}

public function testExceptionOnExecution(): void
#[Test]
public function exceptionOnExecution(): void
{
$this->em
->expects(self::once())
Expand All @@ -130,7 +134,8 @@ public function testExceptionOnExecution(): void
self::assertStringContainsString('test', $output);
}

public function testInvalidEnumTypeArgument(): void
#[Test]
public function invalidEnumTypeArgument(): void
{
$result = $this->commandTester->execute(
[
Expand All @@ -144,7 +149,8 @@ public function testInvalidEnumTypeArgument(): void
self::assertStringContainsString('Argument "enumType" is not a string.', $output);
}

public function testExceptionNotRegisteredEnumType(): void
#[Test]
public function exceptionNotRegisteredEnumType(): void
{
$result = $this->commandTester->execute(
[
Expand All @@ -158,27 +164,8 @@ public function testExceptionNotRegisteredEnumType(): void
self::assertStringContainsString('Argument "enumType" is not a registered ENUM type.', $output);
}

public function testMissingDatabasePlatformForConnection(): void
{
$this->connection
->expects(self::once())
->method('getDatabasePlatform')
->willReturn(null)
;

$result = $this->commandTester->execute(
[
'command' => $this->command->getName(),
'enumType' => 'TaskStatusType',
]
);
self::assertSame(3, $result);

$output = $this->commandTester->getDisplay();
self::assertStringContainsString('Missing database platform for connection.', $output);
}

public function testExecutionWithCaughtException(): void
#[Test]
public function executionWithCaughtException(): void
{
$this->connection
->expects(self::once())
Expand All @@ -198,7 +185,8 @@ public function testExecutionWithCaughtException(): void
self::assertStringContainsString('test', $output);
}

public function testSuccessfulExecutionWithNoMetadata(): void
#[Test]
public function successfulExecutionWithNoMetadata(): void
{
$this->connection
->expects(self::once())
Expand Down Expand Up @@ -226,7 +214,9 @@ public function testSuccessfulExecutionWithNoMetadata(): void
self::assertStringContainsString('NO METADATA FOUND', $output);
}

public function testSuccessfulExecutionWithMetadata(): void
#[Test]
#[DataProvider('dataProviderForMetadataTest')]
public function successfulExecutionWithMetadata(?string $schemaName, string $sqlColumnComment): void
{
$this->connection
->expects(self::once())
Expand All @@ -242,12 +232,15 @@ public function testSuccessfulExecutionWithMetadata(): void
;

$metadata->expects(self::once())->method('getName')->willReturn('Task');
$metadata->expects(self::atLeast(1))->method('getSchemaName')->willReturn($schemaName);
$metadata->expects(self::once())->method('getTableName')->willReturn('tasks');
$metadata->expects(self::once())->method('getFieldNames')->willReturn(['status']);
$metadata->expects(self::once())->method('getTypeOfField')->with('status')->willReturn('TaskStatusType');
$metadata->expects(self::once())->method('getFieldMapping')->with('status')->willReturn(FieldMapping::fromMappingArray(['type'=> 'string', 'columnName' => 'task_column_name', 'fieldName' => 'test']));
$metadata->expects(self::once())->method('getFieldMapping')->with('status')->willReturn(
FieldMapping::fromMappingArray(['type'=> 'string', 'columnName' => 'task_column_name', 'fieldName' => 'test'])
);

$this->platform->expects(self::once())->method('getCommentOnColumnSQL')->with('tasks', 'task_column_name', null)->willReturn('test SQL');
$this->platform->expects(self::once())->method('getCommentOnColumnSQL')->with($sqlColumnComment, 'task_column_name', 'NULL')->willReturn('test SQL');

$this->connection->expects(self::once())->method('executeQuery')->with('test SQL');

Expand All @@ -266,4 +259,28 @@ public function testSuccessfulExecutionWithMetadata(): void
self::assertStringContainsString('TOTAL: 1', $output);
self::assertStringContainsString('DONE', $output);
}

public static function dataProviderForMetadataTest(): iterable
{
yield 'no schema' => [
'schemaName' => null,
'sqlColumnComment' => 'tasks',
];
yield 'public schema' => [
'schemaName' => 'public',
'sqlColumnComment' => 'public.tasks',
];
yield 'custom schema' => [
'schemaName' => 'custom',
'sqlColumnComment' => 'custom.tasks',
];
}

#[Test]
public function autocomplete(): void
{
$enumTypes = $this->command->getEnumTypesForAutocompletion()();

self::assertSame(['BasketballPositionType', 'TaskStatusType'], $enumTypes);
}
}
Loading