From 5faeb5dd568bb0e4922282967fd6105fbb5827af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Tue, 5 Dec 2023 21:33:29 +0100 Subject: [PATCH] Fixed problem with loading Fixtures on MySQL in combination with savepoints We must now load the fixtures using custom command partdb:fixtures:load --- .github/workflows/tests.yml | 5 +- config/services.yaml | 2 +- src/Command/LoadFixturesCommand.php | 76 +++++++++++++++++++ src/Doctrine/Purger/DoNotUsePurgerFactory.php | 53 +++++++++++++ .../Purger/ResetAutoIncrementORMPurger.php | 1 - 5 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 src/Command/LoadFixturesCommand.php create mode 100644 src/Doctrine/Purger/DoNotUsePurgerFactory.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ef2cea33..e062f169 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -107,9 +107,10 @@ jobs: - name: Do migrations run: php bin/console --env test doctrine:migrations:migrate -n - + + # Use our own custom fixtures loading command to circumvent some problems with reset the autoincrement values - name: Load fixtures - run: php bin/console --env test doctrine:fixtures:load -n + run: php bin/console --env test partdb:fixtures:load -n - name: Run PHPunit and generate coverage run: ./bin/phpunit --coverage-clover=coverage.xml diff --git a/config/services.yaml b/config/services.yaml index ccfe14a0..88f13415 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -397,4 +397,4 @@ when@test: arguments: - '@doctrine.fixtures.loader' - '@doctrine' - - { default: '@App\Doctrine\Purger\ResetAutoIncrementPurgerFactory' } \ No newline at end of file + - { default: '@App\Doctrine\Purger\DoNotUsePurgerFactory' } \ No newline at end of file diff --git a/src/Command/LoadFixturesCommand.php b/src/Command/LoadFixturesCommand.php new file mode 100644 index 00000000..e556aec4 --- /dev/null +++ b/src/Command/LoadFixturesCommand.php @@ -0,0 +1,76 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Command; + +use App\Doctrine\Purger\ResetAutoIncrementORMPurger; +use App\Doctrine\Purger\DoNotUsePurgerFactory; +use App\Doctrine\Purger\ResetAutoIncrementPurgerFactory; +use Doctrine\Bundle\FixturesBundle\Purger\ORMPurgerFactory; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * This command does basically the same as doctrine:fixtures:load, but it purges the database before loading the fixtures. + * It does so in another transaction, so we can modify the purger to reset the autoincrement, which would not be possible + * because the implicit commit otherwise. + */ +#[AsCommand(name: 'partdb:fixtures:load', description: 'Load test fixtures into the database and allows to reset the autoincrement before loading the fixtures.', hidden: true)] +class LoadFixturesCommand extends Command +{ + public function __construct(private readonly EntityManagerInterface $entityManager) + { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $ui = new SymfonyStyle($input, $output); + + $ui->warning('This command is for development and testing purposes only. It will purge the database and load fixtures afterwards. Do not use in production!'); + + if (! $ui->confirm(sprintf('Careful, database "%s" will be purged. Do you want to continue?', $this->entityManager->getConnection()->getDatabase()), ! $input->isInteractive())) { + return 0; + } + + $factory = new ResetAutoIncrementPurgerFactory(); + $purger = $factory->createForEntityManager(null, $this->entityManager); + + $purger->purge(); + + //Afterwards run the load fixtures command as normal, but with the --append option + $new_input = new ArrayInput([ + 'command' => 'doctrine:fixtures:load', + '--append' => true, + ]); + + $returnCode = $this->getApplication()?->doRun($new_input, $output); + + return $returnCode ?? Command::FAILURE; + } +} \ No newline at end of file diff --git a/src/Doctrine/Purger/DoNotUsePurgerFactory.php b/src/Doctrine/Purger/DoNotUsePurgerFactory.php new file mode 100644 index 00000000..95726fab --- /dev/null +++ b/src/Doctrine/Purger/DoNotUsePurgerFactory.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Purger; + +use Doctrine\Bundle\FixturesBundle\Purger\PurgerFactory; +use Doctrine\Common\DataFixtures\Purger\ORMPurgerInterface; +use Doctrine\Common\DataFixtures\Purger\PurgerInterface; +use Doctrine\ORM\EntityManagerInterface; + +class DoNotUsePurgerFactory implements PurgerFactory +{ + + public function createForEntityManager( + ?string $emName, + EntityManagerInterface $em, + array $excluded = [], + bool $purgeWithTruncate = false + ): PurgerInterface { + return new class() implements ORMPurgerInterface { + + public function purge(): void + { + throw new \LogicException('Do not use doctrine:fixtures:load directly. Use partdb:fixtures:load instead!'); + } + + public function setEntityManager(EntityManagerInterface $em) + { + // TODO: Implement setEntityManager() method. + } + }; + } +} \ No newline at end of file diff --git a/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php b/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php index 755fd553..fe625b2a 100644 --- a/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php +++ b/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php @@ -190,7 +190,6 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface //Reseting autoincrement is only supported on MySQL platforms if ($platform instanceof AbstractMySQLPlatform ) { //|| $platform instanceof SqlitePlatform) { - $connection->beginTransaction(); $connection->executeQuery($this->getResetAutoIncrementSQL($tbl, $platform)); } }