Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Awesome Random Fixtures

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Look at ArticleFixtures: we created 10 articles. So, the system has references from 0 to 9:

... lines 1 - 8
class ArticleFixtures extends BaseFixture
{
... lines 11 - 27
public function loadData(ObjectManager $manager)
{
$this->createMany(Article::class, 10, function(Article $article, $count) use ($manager) {
... lines 31 - 60
});
... lines 62 - 63
}
}

In CommentFixture, spice things up: replace the 0 with $this->faker->numberBetween(0, 9):

... lines 1 - 8
class CommentFixture extends BaseFixture
{
protected function loadData(ObjectManager $manager)
{
$this->createMany(Comment::class, 100, function(Comment $comment) {
... lines 14 - 19
$comment->setArticle($this->getReference(Article::class.'_'.$this->faker->numberBetween(0, 9)));
});
... lines 22 - 23
}
}

Try the fixtures again:

php bin/console doctrine:fixtures:load

No errors! And... check the database:

php bin/console doctrine:query:sql 'SELECT * FROM comment'

That is much better! Just like that, each comment is related to a random article!

Making this Random Reference System Reusable

I really like this idea, where we can fetch random objects in our fixtures. So, let's make it easier! In BaseFixture, add a new private property on top called $referencesIndex. Set that to an empty array:

... lines 1 - 9
abstract class BaseFixture extends Fixture
{
... lines 12 - 17
private $referencesIndex = [];
... lines 19 - 60
}

I'm adding this because, at the bottom of this class, I'm going to paste in a new, method that I prepared. It's a little ugly, but this new getRandomReference() does exactly what its name says: you pass it a class, like the Article class, and it will find a random Article for you:

... lines 1 - 9
abstract class BaseFixture extends Fixture
{
... lines 12 - 17
private $referencesIndex = [];
... lines 19 - 41
protected function getRandomReference(string $className) {
if (!isset($this->referencesIndex[$className])) {
$this->referencesIndex[$className] = [];
foreach ($this->referenceRepository->getReferences() as $key => $ref) {
if (strpos($key, $className.'_') === 0) {
$this->referencesIndex[$className][] = $key;
}
}
}
if (empty($this->referencesIndex[$className])) {
throw new \Exception(sprintf('Cannot find any references for class "%s"', $className));
}
$randomReferenceKey = $this->faker->randomElement($this->referencesIndex[$className]);
return $this->getReference($randomReferenceKey);
}
}

That's super friendly!

In CommentFixture, use it: $comment->setArticle() with $this->getRandomReference(Article::class):

... lines 1 - 8
class CommentFixture extends BaseFixture
{
protected function loadData(ObjectManager $manager)
{
$this->createMany(Comment::class, 100, function(Comment $comment) {
... lines 14 - 19
$comment->setArticle($this->getRandomReference(Article::class));
});
... lines 22 - 23
}
}

To make sure my function works, try the fixtures one last time:

php bin/console doctrine:fixtures:load

And, query for the comments:

php bin/console doctrine:query:sql 'SELECT * FROM comment'

Brilliant!

Fixture Ordering

There is one last minor problem with our fixtures... they only work due to pure luck. Check this out: I'll right click on CommentFixture and rename the class to A0CommentFixture:

... lines 1 - 9
class A0CommentFixture extends BaseFixture implements DependentFixtureInterface
{
... lines 12 - 30
}

Also allow PhpStorm to rename the file. Some of you might already see the problem. Try the fixtures now:

php bin/console doctrine:fixtures:load

Bah! Explosion!

Cannot find any references to App\Entity\Article

The error comes from BaseFixture and it basically means that no articles have been set into the reference system yet!

... lines 1 - 9
abstract class BaseFixture extends Fixture
{
... lines 12 - 41
protected function getRandomReference(string $className) {
... lines 43 - 52
if (empty($this->referencesIndex[$className])) {
throw new \Exception(sprintf('Cannot find any references for class "%s"', $className));
}
... lines 56 - 59
}
}

You can see the problem in the file tree. We have not been thinking at all about what order each fixture class is executed. By default, it loads them alphabetically. But now, this is a problem! The A0CommentFixture class is being loaded before ArticleFixtures... which totally ruins our cool system!

You can also see this in the terminal: it loaded A0CommentFixture first.

DependentFixtureInterface

The solution is pretty cool. As soon as you have a fixture class that is dependent on another fixture class, you need to implement an interface called DependentFixtureInterface:

... lines 1 - 6
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
... lines 8 - 9
class A0CommentFixture extends BaseFixture implements DependentFixtureInterface
{
... lines 12 - 30
}

This will require you to have one method. Move to the bottom, then, go to the "Code" -> "Generate" menu, or Command + N on a Mac, select "Implement Methods" and choose getDependencies(). I'll add the public before the function:

... lines 1 - 9
class A0CommentFixture extends BaseFixture implements DependentFixtureInterface
{
... lines 12 - 26
public function getDependencies()
{
... line 29
}
}

Just return an array with ArticleFixtures::class:

... lines 1 - 9
class A0CommentFixture extends BaseFixture implements DependentFixtureInterface
{
... lines 12 - 26
public function getDependencies()
{
return [ArticleFixtures::class];
}
}

That's it! Load them again:

php bin/console doctrine:fixtures:load

Bye bye error! It loaded ArticleFixtures first and then the comments below that. The fixtures library looks at all of the dependencies and figures out an order that makes sense.

With that fixed, let's rename the class back from this ridiculous name to CommentFixture:

... lines 1 - 9
class CommentFixture extends BaseFixture implements DependentFixtureInterface
{
... lines 12 - 30
}

To celebrate, move over, refresh and... awesome! 8, random comments. We rock!

Next, let's learn about some tricks to control how Doctrine fetches the comments for an article, like, their order.

Leave a comment!

44
Login or Register to join the conversation

Hey Denis,

Could you explain exactly what you renamed to what? Like name and new name... It's important to know so we could be able to help you. Most probably you renamed it bad, e.g. class name does not match file name, etc. Or probably you renamed the class, but still reference the old name somewhere.

Cheers!

1 Reply
GDIBass Avatar
GDIBass Avatar GDIBass | posted 5 years ago

If anyone's like me and going through this before it's finished and would like an example for the getRandomReference function, here you go:

protected function getRandomReference($class)
{
$all = $this->manager->getRepository($class)->findAll();
return $all[array_rand($all)];
}

1 Reply

Haha, hey again GDIBass! I'm also happy to post our version, fwiw. It looks like this:


abstract class BaseFixture extends Fixture
{
    // ...
    private $referencesIndex = [];

    // ...

    protected function getRandomReference(string $className) {
        if (!isset($this->referencesIndex[$className])) {
            $this->referencesIndex[$className] = [];
            
            foreach ($this->referenceRepository->getReferences() as $key => $ref) {
                if (strpos($key, $className.'_') === 0) {
                    $this->referencesIndex[$className][] = $key;
                }   
            }   
        }   
        
        if (empty($this->referencesIndex[$className])) {
            throw new \Exception(sprintf('Cannot find any references for class "%s"', $className));   
        }
        
        $randomReferenceKey = $this->faker->randomElement($this->referencesIndex[$className]);    

        return $this->getReference($randomReferenceKey);
    }
}

Cheers!

2 Reply
GDIBass Avatar

Thank you!

Reply
Default user avatar
Default user avatar Uli Hecht | posted 1 year ago | edited

The logic here is to generate fixtures for related entities separately. This is very time consuming and counter intuitive for me. For example, I generate invoices and those invoices have items. My goal is to generate invoices that are meaningful and consistent. With the solutions suggested here invoices could have no items at all. Also I have a related "Offer" entity with an expected billing amount. The invoice items' total amount should (at least almost) match with the offer amount in meaningful cases.

My point is:

It would be far easier for me to generate the fixtures this way:


$invoice = new Invoice();
$amount = 0;
// repeat
    $invoiceItem = new InvoiceItem();
    // ...
    $invoice->addItem($invoiceItem);
    $amount += $invoiceItem->getAmount();
// ...
$offer = new Offer();
$offer->setTotalAmount($amount);
// ...
$invoice->setOffer($offer);

But it feels a bit like this is against best practices. Or is this a false impression and my suggested solution is also reasonable?

<s>Second question: Why isgetRandomReference() implementing a "cache" ($referencesIndex)? Is a plain call to referenceRepository->getReference() expensive?</s>
Edited: This is not caching the references but their indices.

Reply

Hey Uli Hecht!

> But it feels a bit like this is against best practices. Or is this a false impression and my suggested solution is also reasonable?

I think they way you want to create the fixtures is TOTALLY fine. There is no best practice that you're violating, imo. It is just that, in many situations, it's nice to organize your fixtures by entity. But your example of an Invoice with InvoiceItems is a perfect example of something that you would want to keep together, so do it :).

Cheers!

2 Reply

Hey Farry7,

Please, double check your migration. Looks like it's not perfect, it may work on the empty database, but because you have some data there - it fails. I'd recommend you to check that FK_2CE0D8114D5B19A3 constraint and see its related columns, there's some a problem with relations.

I hope this helps!

Cheers!

Reply
Farshad Avatar
Farshad Avatar Farshad | posted 2 years ago

All of this is outdated now in Symfony 5, I guess? Because I was using AppFixtures and Factory in another tutorial.

Reply

Hey Farry,

I wouldn't say it's all outdated, most of the content is still relevant, although, you may encounter with a few deprecations here and there, but when in doubt, you can always ask us your questions

Cheers!

Reply

Heya @weaverryan yo a question, the variable $count in createmany is usable to print the current position in the loop?

another question, how about I want to have a value in the database called "number" that has nothing to do with ID, so I want each new insert, to be equal to "last record inserted +1", for example.

a Web Novel has a title, a description an image, and it has chapter, so I have a novel entity and a chapter entity.
the chapter entity has a field called "number" for "Chapter Number" related to that specific "novel"

how do I go around, checking that "the current chapter inserted belongs to XX novel, so I want to get the last inserted "number" value, related to the XX novel, and then set this NEW insert to "latest chapter number for novel XX + 1"

dont know if im explaining myself properly.

Reply

jlchafardet @everyone

Now I'm sitting on an entirely different problem.

When I try to run fixtures now, with 2 fixtures requiring relationships (using DependentFixtureInterface and the new method getDependencies) it errors me saying that it cannot find an entity thats attempted to be loaded.

josec@Josefo-Desktop: /D/vhosts/novelreader
$ bin/console doctrine:fixtures:load

In SymfonyFixturesLoader.php line 76:

The "App\Entity\Novel" fixture class is trying to be loaded, but is not available. Make sure thi
s class is defined as a service and tagged with "doctrine.fixture.orm".

josec@Josefo-Desktop: /D/vhosts/novelreader
$

so let me show you my code.

AuthorFixtures no need for relations yet imho as I dont have to add novels nor chapters to add an author.

NovelFixtures https://pastebin.com/58NjFGEC
ChapterFixtures https://pastebin.com/AHLTs9bw

BaseFixture https://pastebin.com/rfprPd8r

The error is as stated above, whenever I try to run the fixtures, I get the error that the Entity Novel is trying to be loaded but not available, when it actually is.

Reply

oh mah gawd! I found the problem, I was trying to use the entities themselves, not the fixtures when calling the dependencies, as soon as I realized that I was doing return [novel::class] instead of [NovelFixtures::class] i changed it, and presto, worked.

now, the issue I have is, with fixtures, when adding chapters, I need the field "number" to start from 1 for each "new" novel, then add 1 to the previously added number, so each chapter thats added, is incrementally numbered "in a per novel manner".

what I mean is, if there are 20 novels, and each novel has more than 3 chapters, there will be 20 chapters "numbered" 1, 2 and 3, its just that they are "related" to a specific novel.

does that makes any sense at all to you?

Reply

Hey JLChafardet,

Haha, tricky misprint but you caught it, good job! :)

I think I got it! Hm, well, first of all, if your fixtures are simple - you can write them in the same fixtures file, like create both Novel and Chapter entities in the same fixtures class, then probably it would be easier to do what you want :)

Otherwise, you just need to play in ChapterFixtures and create Chapter entities in a loop but every new 4th iteration you need to start from 1 again. You can use a separate variable that you will manually increment and re-set in the loop :)

I hope this helps!

Cheers!

1 Reply

Yeah I think I get the idea of what you are proposing, anyway as its for testing purposes, for now, I just lowered the amount of chapters and novels, that way I dont have to sweat much about it. so I can easily go to phpmyadmin and change the chapter number of each novel, that way I can test what I really want, which is the "next, prev" buttons, so you can go straight to the next or previous chapter of a specific novel.

this is an internal "for my own entertainment" work that I'm doing, so I'm using it as both a learning and practicing experiment.

Reply

Hey JLChafardet,

Yeah, if you want to do this tweak only once - sounds good to do it directly in the DB... but if you need those tweaks every time you load fixtures and you do it often - it definitely worth to do in fixtures :)

Cheers!

Reply
Christina V. Avatar
Christina V. Avatar Christina V. | posted 3 years ago | edited

Hi all !

I'm trying to use these tutorials, and adapt it to my own use.
So... I'm trying to have create datas for User.

When I load the fixtures, referring to my terminal, I have this:

purging database
loading App\DataFixtures\UserGroupFixtures
loading App\DataFixtures\UserFixtures

Which seems to be correct since I have 2 fixtures files:

<b> UserGroupFixtures </b>

`
<?php

namespace App\DataFixtures;

use App\Entity\UserGroup;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;

/**

  • Class UserGroupFixtures
  • @package App\DataFixtures
    / class UserGroupFixtures extends Fixture { /*

    • @param ObjectManager $manager
      */
      public function load(ObjectManager $manager)
      {

      /** @var UserGroup $adminUserGroup */
      $adminUserGroup = new UserGroup();
      $adminUserGroup->setTitle('admin');

      $manager->persist($adminUserGroup);

      /** @var UserGroup $adminUserGroup */
      $userUserGroup = new UserGroup();
      $userUserGroup->setTitle('user');

      $manager->persist($userUserGroup);

      /** @var UserGroup $adminUserGroup */
      $viewerUserGroup = new UserGroup();
      $viewerUserGroup->setTitle('viewer');

      $manager->persist($viewerUserGroup);

      $manager->flush();
      }
      }

`

<b>UserFixtures</b>

`
<?php

namespace App\DataFixtures;

use App\Entity\User;
use App\Entity\UserGroup;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class UserFixtures extends BaseFixture implements DependentFixtureInterface
{

/**
 * @var array
 */
private static $userRoles = [
    ["ROLE_ADMIN"],
    ["ROLE_USER"]
];

/**
 * @var array
 */
private static $userInsertion = [
    'van',
    'de',
    ''
];

private $passwordEncoder;

/**
 * UserFixtures constructor.
 * @param UserPasswordEncoderInterface $passwordEncoder
 */
public function __construct(UserPasswordEncoderInterface $passwordEncoder)
{
    $this->passwordEncoder = $passwordEncoder;
}

/**
 * @param ObjectManager $manager
 */
protected function loadData(ObjectManager $manager)
{
    $this->createMany(User::class, 10, function(User $user) use ($manager) {

        $user->setUsername($this->faker->userName);
        $user->setRoles($this->faker->randomElement(self::$userRoles));
        $user->setPassword($this->passwordEncoder->encodePassword($user, 'ACTIVO'));
        $user->setFirstname($this->faker->firstName);
        $user->setLastname($this->faker->lastName);
        $user->setInsertion($this->faker->randomElement(self::$userInsertion));
        $user->setEmail($this->faker->email);
        $user->setDateCreated($this->faker->dateTime);
        $user->setDateUpdate($this->faker->dateTime);
        $user->setUnsubscribed($this->faker->boolean(15));
        $user->setDateUnsubscribed($this->faker->dateTime);

        $user->setUserGroup($this->getRandomReference(UserGroup::class));
    });

    $manager->flush();
}

/**
 * @return array|string
 */
public function getDependencies()
{
    return [UserGroupFixtures::class,];
}

}
`

But still.... I have this error:

<b>Cannot find any references for class "App\Entity\UserGroup"</b>

Is there anybody having an idea ?
Thanks for your help

Reply

Hey Christina,

I see you call getRandomReference(UserGroup::class) in UserFixtures, but I don't see you add that reference in UserGroupFixtures. We do it behind the scene in createMany() method, see addReference call in this class (better to expand all lines in that code block to see the full picture):
https://symfonycasts.com/sc... . So, if you do not call that createMany(), then you would probably need to call that addReference() method manually to create the reference first.

I hope this helps!

Cheers!

Cheers!

Reply
Ozornick Avatar
Ozornick Avatar Ozornick | posted 4 years ago | edited

` public function getDependencies()

{
    return [ArticleFixture::class];
}`

in the end code. ArticleFixture<b>s</b>?

Reply

Hey Ozornick

Awesome catch! Thanks for your attention! We fixed it!

Cheers!

1 Reply
Robert Avatar

Thank you.

Reply
picks Avatar
picks Avatar picks | posted 4 years ago | edited

Hi! Looks like the getRandomReference() function only works on ManyToOne relations... I'm using a OneToOne relation and the $this->faker->randomElement() makes the command doctrine:fixtures:load throw this error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '61' <br /> for key 'UNIQ_4B6C0887A76ED395'
How can I adapt it to work for any relation type?

Reply

Hey picks

That's a good question. I think what you can do is to create a new method that duplicates the logic of getRandomReference but it removes the fetched reference from referencesIndex property. Give it a try and let us know if it worked :)

Cheers!

Reply

Hi! Unfortunaly I can't find the tutorial when you have started to use Fixtures, so I have copied the BaseFixture and create a UserFixture like you have done. Yet when I try to run the command load fixtures I get this error:
In BaseFixture.php line 12:

Attempted to load class "Factory" from namespace "Faker".
Did you forget a "use" statement for "Doctrine\Migrations\
Version\Factory"?

Can you help me?

Reply

Hey Gballocc7

That error makes me believe that you don't have Fake installed or for some reason you forgot to copy the use statements from BaseFixture file. Give it a check and let us know if the error continues

Cheers!

Reply

Solved, thanks! Now I can't execute the load fixture look at that:

Using UserFixtures:

$this->createMany(User::class,3 , function($i) {
$user = new User();
$user->setUsername(sprintf('prova', $i));
$user->setRoles(["USER_ROLE"]);
$user->setPassword($this->passwordEncoder->encodePassword(
$user,
'prova'
));
return $user;
});

And I get:

In AbstractMySQLDriver.php line 103:

An exception occurred while executing 'INSERT INTO user (username, roles, password) VALUES (
?, ?, ?)' with params [null, "[]", null]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'username' cannot be null

In PDOStatement.php line 119:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'username' cannot be null

In PDOStatement.php line 117:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'username' cannot be null

How??

Reply

Hey Giacomo,

I see it's a duplicate of: https://symfonycasts.com/sc...

Let's continue discuss it there to avoid fixing this problem in a few places.

Cheers!

1 Reply
sadikoff Avatar sadikoff | SFCASTS | posted 4 years ago | edited

hey there

This is super weird =) But I have probably a solution for you

  1. save all your modified files
  2. download course code
  3. restore your files
  4. run composer install (!!!not update needed)
  5. If issue still will be here, than it will be perfect if you share all your project files via github

Cheers!

Reply
sadikoff Avatar sadikoff | SFCASTS | posted 4 years ago | edited

hey there

It's a little weird, but I tried your code locally and everything works as expected, Could you please share your php -v output?

Cheers!

Reply
Max S. Avatar

Is it possible to get the same error due to using php 7.2.18?

Reply

I think it's possible with any version of PHP it looks like some cache issue have you tried solution from comments below?

Reply
akincer Avatar
akincer Avatar akincer | posted 4 years ago

Hmm, now I'm getting this error on fixtures load after switching over to the dependencies code near the end.

PHP Fatal error: Class App\DataFixtures\PostFixtures contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Doctrine\Common\DataFixtures\DependentFixtureInterface::getDependencies) in /var/www/dev/svfx/src/DataFixtures/PostFixtures.php on line 51

Reply

Hey Aaron,

I don't see we have PostFixtures in the course code. Please, look at parent classes and find the abstract method that is not implemented in your final PostFixtures class. I think PhpStorm may help with it, go to "Generate" menu or press Cmd + N on a Mac, and choose "Implement methods" - you will be suggested to choose what methods you need to implement. Also, I suppose your PostFixtures should be underlined with a red wavy line, if you hover over it - PhpStorm will suggest you what abstract method you have to implement. You can also look inside our any fixture class, e.g. ArticleFixtures to see what methods are implemented there and what's exact implementation of it.

Cheers!

Reply
akincer Avatar

FYI -- fixed it by returning AppFixtures as a dependency for ArticleFixtures equivalent.

Reply

Hey Aaron, if your fixture class doesn't have any dependencies, then it must not implement the DependentFixtureInterface

Reply
akincer Avatar

I chose a different name other than "Article" and instead used "Post" because I'm going to leverage the services I build in this tutorial as a foundation for a site where "Post" makes more sense than "Article". Anyway, I did generate and that definitely is the problem for the Article class equivalent. Although it's demanding I return a class in an array. Returning nothing and an empty array both give different errors.

I don't see anything in the tutorial covering this case, so I'm guessing the behavior changed from when this was created and the current stable version of Symfony/Doctrine?

Reply
Default user avatar
Default user avatar Kristof Kreimeyer | posted 4 years ago

Hey guys,

when i implement the getDependencies() function and return [ArticleFixture::class] i get this error in my console:

In Loader.php line 321:

Fixture "App\DataFixtures\ArticleFixture" was declared as a dependency, but it should be added in fixture loader fi
rst.

Adding to that IntelliJ also tells me that ArticleFixture is a undefined class

Reply

Hey Kristof!

Try ArticleFixtures with an “s”. I’m afraid that I was accidentally a bit inconsistent and used the s on some fixture classes but not others - if you’re following the code, this one should end in an s.

Let me know if that helps!

Cheers!

Reply
Default user avatar
Default user avatar Kristof Kreimeyer | weaverryan | posted 4 years ago

yeah that was the error :) thx Ryan

Reply
Otto K. Avatar
Otto K. Avatar Otto K. | posted 4 years ago

Why I can't see my "AuthorsName" ?
If load DATA from "BaseFixture" it's work (prev. course)

createMany(Comment::class, 7, function(Comment $comment) {
$comment->setStatus(1);
// $comment->setAuthor($this->faker->AuthorsName);

Reply

Hey Student!

What exactly code do you have? As I see in your comment, you commented out the line with setAuthor(). Could you give us a bit more context?

Cheers!

Reply
skatAn8rwpos Avatar
skatAn8rwpos Avatar skatAn8rwpos | posted 5 years ago

Hi.. I am getting this in th console when i use in my fixture the when i use the

getRandomReference(Article::calss). (edit: Woooorks!!)

Booooooo!!!!!
-------------------------------------------------------------------------------
In ReferenceRepository.php line 167: Warning:

Illegal offset type in isset or empty

--------------------------------------------------------------------------------
using the getReference(Article::class . '_' . $this->faker->numberBetween(0, 9) Woooorks!!

I'm on symfony 4.1.2. upgraded today...
because I had a Deprecation Log Message in the Profiler:
----------------------------------------------------------------------------------------
User Deprecated: Doctrine\Common\ClassLoader is deprecated.
----------------------------------------------------------------------------------------

Am I the only I see it???
What may I do wrong...?
_______________________________________________________________
edit:
I found what i did..
geReference( getRandomReference() )

-- NEVER do that --

Reply

Ohh, you were trying to get the reference of a reference... yeah, it sound's like the system may behave weird

Reply
Luis M. Avatar
Luis M. Avatar Luis M. | posted 5 years ago | edited

Hi!!!

For me is confusing a method that sets and gets data. Wouldn't be clearer to have two methods?

  1. protected function pushToReferencesIndex(string $className, $entity): void that would call to addReference and add the key to the reference index:

{
       $className.'_'.$i, $entity;
       $this->addReference($key);
       if (!isset($this->referencesIndex[$className])) {
            $this->referencesIndex[$className] = [];
       }
      $this->referencesIndex[$className][] = $key;
}
  1. protected function getRandomReference(string $className): object that would only have this lines:
    
    

{

    if (empty($this->referencesIndex[$className])) {
        throw new \Exception(sprintf('Cannot find any references for class "%s"', $className));
    }
    $randomReferenceKey = $this->faker->randomElement($this->referencesIndex[$className]);
    return $this->getReference($randomReferenceKey);

}



Or maybe just leave things equal and not do some over-engineering?
Reply

Hey Luis M.!

Yea, I think this certainly makes sense :). I was really "working around" the fact that the normal addReference() method doesn't give us any "hook" or easy way to "fetch" references out (it's just one big array). But, we could set referencesIndex() from inside of createMany() to avoid needing to build this array later :). I wouldn't worry too much about a method that sets & gets data - the referencesIndex() is more of an "internal cache" to help us out. However, certainly your suggestion makes sense!

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

The course is built on Symfony 4, but the principles still apply perfectly to Symfony 5 - not a lot has changed in the world of relations!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "knplabs/knp-paginator-bundle": "^2.7", // v2.7.2
        "knplabs/knp-time-bundle": "^1.8", // 1.8.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.1.4
        "stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
        "symfony/asset": "^4.0", // v4.0.4
        "symfony/console": "^4.0", // v4.0.14
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/framework-bundle": "^4.0", // v4.0.14
        "symfony/lts": "^4@dev", // dev-master
        "symfony/orm-pack": "^1.0", // v1.0.6
        "symfony/twig-bundle": "^4.0", // v4.0.4
        "symfony/web-server-bundle": "^4.0", // v4.0.4
        "symfony/yaml": "^4.0", // v4.0.14
        "twig/extensions": "^1.5" // v1.5.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.0.2
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.4
        "fzaninotto/faker": "^1.7", // v1.7.1
        "symfony/debug-bundle": "^3.3|^4.0", // v4.0.4
        "symfony/dotenv": "^4.0", // v4.0.14
        "symfony/maker-bundle": "^1.0", // v1.4.0
        "symfony/monolog-bundle": "^3.0", // v3.1.2
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.0.4
        "symfony/profiler-pack": "^1.0", // v1.0.3
        "symfony/var-dumper": "^3.3|^4.0" // v4.0.4
    }
}
userVoice