Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I override auto increment ID with Alice Fixtures?

I am using Symfony2 with Doctrine and I'm using the Alice Fixture bundle to generate my fixtures for testing.

In one case I need to create a fixture where the id is 148 for a specific test. All of our ids are configured to auto_increment, so I am currently creating 147 dummy records just to create the one I need.

I was hoping to use this definition to force the id to be set to 148:

 invoiceClassNoClass (extends invoiceClass):
    id: 148
    sortOrder: 1
    label: 'No Class'

Unfortunately this does not work. From a google search I read a brief comment stating that I first need to add a setId method to my entity. I tried that but it did not make a difference. In reality I do not want to add as setId method if I do not need to, as it violates our integrity rules where we never allow the setting of an id.

Perhaps there is reflection class that could be used? Perhaps this is built into Alice and I do not know about it?

like image 585
kc_rob Avatar asked Apr 29 '16 15:04

kc_rob


3 Answers

I also ran into this issue since I wanted some ids to be the same every run since I want to refer them in my debug apps using the UUID strategy.

What I have done:

1) Wrote a command that wraps hautelook:fixtures:load:

protected function execute(InputInterface $input, OutputInterface $output)
{
    $container     = $this->getContainer();
    $entityManager = $container->get('doctrine.orm.default_entity_manager');

    $metadata = $entityManager->getClassMetaData(App::class);
    $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
    $metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());

    $application = new Application($kernel);
    $application->setAutoExit(false);

    $this->loadFixtures($application, $output);
}

Do the $metadata-stuff for all classes you want to have custom ids (App::class).

protected function loadFixtures(Application $application, OutputInterface $output)
{
    $loadFixturesInput = new ArrayInput(array(
        'command' => 'hautelook:fixtures:load',
        '--no-interaction' => 'true',
        '--verbose' => '3'
    ));

    $application->run($loadFixturesInput, $output);
}

2) I created a template to generate the id like doctrine would.

id (template):
    id (unique):   '<uuid()>'

3) In my custom entity fixture, now I can do the following:

app_custom (extends id):
    id:    'whatever-i-want'
    title: 'My custom entity'

4) And if I don't want to use a custom id, I just don't overwrite the id field:

app_another (extends id):
    title: 'Just another app with an id I do not care about'

Proof:

enter image description here

like image 56
Thomas Kekeisen Avatar answered Oct 18 '22 03:10

Thomas Kekeisen


If you want doctrine to save a certain value for an auto increment Id, then you have to deactivate auto increment in doctrine metadata. See

Explicitly set Id with Doctrine when using "AUTO" strategy

$this->em->persist($entity);

$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
like image 42
Carsten Ulrich Avatar answered Oct 18 '22 03:10

Carsten Ulrich


UPDATE: After further research on the subject, I realised that hardcoding ids in fixtures comes with its own problems and is generally not a good idea. Instead, it's better to get fixtures by their reference in the yml file when you need to check for a specific record.


Since the question is about the Alice fixtures bundle, I found the following to work for me:

protected $idGeneratorTypes = [];

protected function allowFixedIdsFor(array $entityClasses)
{
    $em = $this->getContainer()->get('doctrine')->getManager();
    foreach ($entityClasses as $entityClass) {
        $metadata = $em->getClassMetadata($entityClass);
        $this->idGeneratorTypes[$entityClass] = $metadata->generatorType;
        $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
    }
}

protected function recoverIdGenerators()
{
    $em = $this->getContainer()->get('doctrine')->getManager();
    foreach ($this->idGeneratorTypes as $entityClass => $idGeneratorType) {
        $metadata = $em->getClassMetadata($entityClass);
        $metadata->setIdGeneratorType($idGeneratorType);
    }
}

Then in the test's setUp() method, I have

    $this->allowFixedIdsFor([
        MyEntity::class,
    ]);


    $this->loadFixtureFiles([
        './tests/DataFixtures/ORM/my_entities.yml',
    ]);

    $this->recoverIdGenerators();

It looks like you don't event need to have a setId() method in your entity.

like image 9
pmishev Avatar answered Oct 18 '22 02:10

pmishev