Skip to content

Commit

Permalink
Upgrade to Symfony 7.1 + new features (#240)
Browse files Browse the repository at this point in the history
  • Loading branch information
fre5h authored May 31, 2024
1 parent 272f0c7 commit 038bcc3
Show file tree
Hide file tree
Showing 21 changed files with 230 additions and 150 deletions.
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

0 comments on commit 038bcc3

Please sign in to comment.