Skip to content

feat: add --dry-run option #512

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

Open
wants to merge 1 commit into
base: 4.2.x
Choose a base branch
from

Conversation

Maxcastel
Copy link

Add --dry-run option to doctrine:fixtures:load command to display loaded fixtures without actually loading them

php bin/console doctrine:fixtures:load --dry-run

closes: #511 #508

@greg0ire
Copy link
Member

greg0ire commented Aug 10, 2025

I think this should rather be done by:

  1. Contributing a DryRunORMExecutor class to doctrine/data-fixtures.
  2. Using it in this bundle.

It could look like this:

final readonly class DryRunORMExecutor extends AbstractExecutor
{
    use ORMExecutorCommon;

    /** @inheritDoc */
    public function execute(array $fixtures, bool $append = false): void
    {
        $executor = $this;
        $this->em->beginTransaction();
        try {
            if ($append === false) {
                $executor->purge();
            }

            foreach ($fixtures as $fixture) {
                $executor->load($em, $fixture);
            }
            $this->em->flush();
        } finally {
            $this->em->close();
            $this->em->rollBack();
        }
    }
}

That way, we avoid nesting transactions (ORMExecutor already creates a transaction), and adding to the user interface layer stuff that does not belong to it. Also, the finally statement ensures the transaction is cleanly rolled back in the instance of an error.

@Maxcastel
Copy link
Author

Thank you for your response @greg0ire.

So it would be something like this:

doctrine/doctrine-fixtures-bundle/src/Command/LoadDataFixturesDoctrineCommand.php:

if ($input->getOption('dry-run')) {
    $ui->text('  <comment>(dry-run)</comment>');
    $executor = new DryRunORMExecutor($em, $purger);
} else {
    $executor = new ORMExecutor($em, $purger);
}

If that's the best solution, I'll implement it.

But doesn't that create repetitive code between DryRunORMExecutor and ORMExecutor?

Wouldn’t it be possible to just modify ORMExecutor (for example, change wrapInTransaction to a manual transaction and add a boolean dryRun parameter) without creating a new DryRunORMExecutor class with code similar to ORMExecutor?

Something like this:

doctrine/data-fixtures/src/Executor/ORMExecutor.php:

final class ORMExecutor extends AbstractExecutor
{
    use ORMExecutorCommon;

    /** @inheritDoc */
    public function execute(array $fixtures, bool $append = false, bool $dryRun = false): void
    {
        $executor = $this;
        $this->em->beginTransaction();
        try {
            if ($append === false) {
                $executor->purge();
            }

            foreach ($fixtures as $fixture) {
                $executor->load($this->em, $fixture);
            }
            $this->em->flush();

            if ($dryRun === true) {
                $this->em->rollBack();
            } else {
                $this->em->commit();
            }
        } catch (\Throwable $e) {   
            $this->em->rollBack();
        } finally {
            $this->em->close();
        }
    }
}

doctrine/doctrine-fixtures-bundle/src/Command/LoadDataFixturesDoctrineCommand.php:

$executor->execute($fixtures, $input->getOption('append'), $input->getOption('dry-run'));

doctrine/data-fixtures/src/Executor/AbstractExecutor.php:

/**
 * Executes the given array of data fixtures.
 *
 * @param FixtureInterface[] $fixtures Array of fixtures to execute.
 * @param bool               $append   Whether to append the data fixtures or purge the database before loading.
 * @param bool               $dryRun   Whether to simulate the execution of the fixtures without making actual changes to the database.
 */
abstract public function execute(array $fixtures, bool $append = false, bool $dryRun = false): void;

@greg0ire
Copy link
Member

So you would change all the children classes of AbstractExecutor?

@Maxcastel
Copy link
Author

So you would change all the children classes of AbstractExecutor?

Yes, or a third parameter dryRun defaulting to false in the execute method of ORMExecutor, without changing execute in AbstractExecutor, to override execute in AbstractExecutor, or your solution with DryRunORMExecutor, what do you prefer?

@greg0ire
Copy link
Member

But doesn't that create repetitive code between DryRunORMExecutor and ORMExecutor?

Common code could be moved in ORMExecutorCommon.

I prefer my solution. If we continue piling up more booleans, the complexity of the method is going to skyrocket.

@Maxcastel
Copy link
Author

Maxcastel commented Aug 13, 2025

@greg0ire
I’ve applied your suggested solution by creating the DryRunORMExecutor class in doctrine/data-fixtures.
See: doctrine/data-fixtures PR #552

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add --dry-run option to doctrine:fixtures:load command
2 participants