1

I have two enity user and post. I am trying to dump dummy data to post table using fixtures. Now, problem is that I could not insert data to author column which holds ManyToOne relation with User entity.

I tried to insert dummy data by passing id directly as follows:

        for($i=0;$i<20;$i++)
        {

            $post = new Post();
            $post->setTitle($this->faker->realText(20));
            $post->setContent($this->faker->text);
            $post->setIsPublished(true);
            $post->setAuthor('1');
            $post->setPublishedAt(new \DateTime());
            $post->setCreatedAt(new \DateTime());
            $post->setUpdatedAt(new \DateTime());
            $manager->persist($post);

            $manager->flush();
        }

But, it is generating error:

Argument 1 passed to App\Entity\Post::setAuthor() must be an instance of App\Entity\User or null, string given

Is there any way to pick one of user from User entity and insert it into the column randomly.

Update:

After looking at this documentation, I am able to provide reference

UserFixtures:

    public const ADMIN_USER_REFERENCE = 'admin-user';

    public function load(ObjectManager $manager)
    {
        ......
        $this->addReference(self::ADMIN_USER_REFERENCE, $userAdmin);
    }

PostFixtures:

$post->setAuthor($this->getReference(UserFixtures::ADMIN_USER_REFERENCE ));

Following, this way it is setting all the posts to the same author. However, I am looking to insert different author randomly throughout different posts.

Aayush Dahal
  • 856
  • 1
  • 17
  • 51

2 Answers2

1

in this case, you have to use reference Symfony Fixtures DOC

Sharing Objects between Fixtures¶

For example, when you create an Author, you can "save" it as a reference like this :

$this->addReference('author-reference', $author);

Then in your other fixture that needs a reference to Author you can do something like this :

$author = $this->getReference('author-reference');

I hope this help you, regards

Alessandro Candon
  • 543
  • 2
  • 6
  • 21
  • Can I use already created users as a reference? By, this technique, it looks like I need to create user again. – Aayush Dahal Mar 03 '19 at 10:40
  • No, you can reference with a tag ( for index ($i) for example ) all created users, and then use this index to retrieve the user reference. – Alessandro Candon Mar 03 '19 at 13:46
  • Does that means I need to create 20 constants for inserting 20 Users as `public const ADMIN_USER_REFERENCE_$i = 'admin-user-$i';` Could you show me the code? – Aayush Dahal Mar 03 '19 at 13:52
1

In order to do this I have a BaseFixture class that has a createMany function

protected function createMany(string $classname, int $count, callable $factory)
{
    for ($i = 0; $i < $count; $i++) {
        $entity = new $classname();
        $factory($entity, $i);

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

        $this->addReference($classname.'_'.$i, $entity);
    }
}

and a getRandomReference function :

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);
}

Now let's say I want to create fixtures for a company class and an address class,

I will first generate the fixtures for the address :

class AddressFixtures extends BaseFixture {
    public function loadData {
        this->createMany(Address::class, 30, function(Address $address, $count) {
       $address->setDescription($this->faker->paragraph);
       ...

        });
    }
}

Because I used the createMany class from the base class the references are now added automatically for each fixture.

we can now get random addresses for our Company fixtures by using the getRandomReference function from our base class :

class CompanyFixtures extends BaseFixture implements DependentFixtureInterface
{
    public function loadData(ObjectManager $manager)
    {
        $company = new Company();
        $company->setAddress($this->getRandomReference(Address::class));
    }
}

I just want to point out that most of this if not all (I can't exactly remember it has been a while) comes from a symfonyCasts tutorial I followed.

Dennis de Best
  • 1,078
  • 13
  • 30