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

Sharing Data between Fixture Classes

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 $12.00

Sharing Data between Fixture Classes

Let’s update the fixtures so that each event has an owner.

We have two fixture classes: one that loads events and one that loads users.

Ordering how Fixtures are Loaded

Start in the LoadUsers class. Now that events depend on users, we’ll want this fixture class to be executed before the events class. To force this, implement a new interface called OrderedFixtureInterface. This requires one method called getOrder. Let’s return 10:

// src/Yoda/UserBundle/DataFixtures/ORM/LoadUsers.php
// ...

use Doctrine\Common\DataFixtures\OrderedFixtureInterface;

class LoadUsers implements FixtureInterface, ContainerAwareInterface, OrderedFixtureInterface
{
    // ...

    public function getOrder()
    {
        return 10;
    }
}

Head over to LoadEvents and make the same change, except returning 20 so that the class is run second:

// src/Yoda/EventBundle/DataFixtures/ORM/LoadEvents.php
// ...

use Doctrine\Common\DataFixtures\OrderedFixtureInterface;

class LoadEvents implements FixtureInterface, OrderedFixtureInterface
{
    // ...

    public function getOrder()
    {
        return 20;
    }
}

Assigning Owners in Fixtures

Now, we just need to get our new User objects inside LoadEvents. DoctrineFixturesBundle has a standard way of sharing data between fixtures, but a much easier way is just to query for our wayne user:

// src/Yoda/EventBundle/DataFixtures/ORM/LoadEvents.php
// ...

class LoadEvents implements FixtureInterface, OrderedFixtureInterface
{
    $wayne = $manager->getRepository('UserBundle:User')
        ->findOneByUsernameOrEmail('wayne');

    // ...
}

All we need to do now is call setOwner on both events so that it looks like wayne created them:

// src/Yoda/EventBundle/DataFixtures/ORM/LoadEvents.php
// ...
public function load(ObjectManager $manager)
{
    $wayne = $manager->getRepository('UserBundle:User')
        ->findOneByUsernameOrEmail('wayne');
    // ...

    $event1->setOwner($wayne);
    $event2->setOwner($wayne);

    // ...
    $manager->flush();
}

Ok! Reload the fixtures!

php app/console doctrine:fixtures:load

Now use app/console to check that each event has an owner:

php app/console doctrine:query:sql "SELECT * FROM yoda_event"

Leave a comment!

12
Login or Register to join the conversation
Dung L. Avatar
Dung L. Avatar Dung L. | posted 2 years ago

Hi Symfonycasts,

I thought the error is simple easy quick fix but I can not find the solution for it, can you please help identify this error for this tutorial?

Thank you!

C:\xampp\htdocs\symfony2\code-symfony2-ep3\finish>php app/console doctrine:fixtures:load
Careful, database will be purged. Do you want to continue Y/N ?Y
> purging database
> loading [10] Yoda\UserBundle\DataFixtures\ORM\LoadUsers
> loading [20] Yoda\EventBundle\DataFixtures\ORM\LoadEvents

[Doctrine\ORM\Query\QueryException]
[Syntax Error] line 0, col -1: Error: Expected Literal, got end of string.

[Doctrine\ORM\Query\QueryException]
SELECT u FROM Yoda\UserBundle\Entity\User u WHERE

doctrine:fixtures:load [--fixtures[="..."]] [--append] [--em="..."] [--purge-with-truncate]

C:\xampp\htdocs\symfony2\code-symfony2-ep3\finish>
Reply

Hey Dung,

Oh boy, this looks like a PHP version compatibility problem. What version of PHP do you use? I guess that some dependencies you have are old enough for your PHP version. There're a few options - you can try to upgrade your dependencies or downgrade your PHP version. The 1st solution would be better I think, I'd recommend you to start with it and see if it helps.

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | victor | posted 2 years ago | edited

Hi victor I upgraded from 2.2.0 to "doctrine/doctrine-fixtures-bundle": "2.4.*@dev", but still no luck. It is ok I will give up on this one since it is not worth the time. Instead I will just listen to the video and learn that way. it has been a few years since symfony 2, now I can see symfony 5 is coming :). Thank you for your help!

Reply

Hey Dung,

Ah, you would need to upgrade to 3.3.0 at least I think, I see it allows doctrine/doctrine-bundle v2.0 which in turn allow Symfony 5 packages, see here: https://packagist.org/packa... . So, yeah, this upgrade process is something that you need to do step by step. The complexity of upgrading depends on how many third-party bundles you have that uses Symfony components. The more you have - the more you nee to upgrade.

Probably some packages are still needed some time to upgrade dependencies to the latest Symfony 5 ones.

So, it's your choice, you can wait or continue to try to upgrade your dependencies earlier. Not sure how many packages you have in your application, but I heard some feedbacks about successfully upgraded applications to Symfony 5 already :)

Maybe we will have a special course about how to upgrade your application to Symfony 5. But I'm not 100% sure about it. Also, we will definitely release new courses about Symfony 5, but we won't explain how to upgrade to Symfony 5 in them.

I hope this helps!

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | victor | posted 2 years ago | edited

Hi victor,

I tried but ran into error again

Fatal error: Out of memory (allocated 1686110208) (tried to allocate 4096 bytes) in phar...

I do not have the need for Symfony2 to work so I will just watch and learn the video and apply in my Symfony4.

Thank you for your time!

Reply

Hey Dung,

Oh, yeah, looks like you need to turn off memory limit for "composer update" command, see Composer's docs about how to do it and choose whatever option is better for you: https://getcomposer.org/doc...

Also, yeah, I noticed that you're looking at Symfony 2 screencasts :) Actually, every time when the new major version of Symfony is released - we record a new screencasts about it. Basically, concepts are the same, but code might be a bit different because some classes/methods might be renamed, new features might be added, etc. So, what I'm trying to say is that you can just go with our Symfony 4 tutorials instead, look into Symfony 4 track: https://symfonycasts.com/tr... - those are the latest screencasts about Symfony :) Soon, we will start releasing Symfony 5 tutorials that just will replace our Symfony 4 ones. So, basically, if you watch the latest course about Symfony and skip old ones - you won't lose a big value. Yes, you might find something interesting in old tutorials, but their value would be pretty little in case you've watched new ones. So, in case you don't have a Symfony 2 project that you would like to deal with - I'd recommend you to start with the latest Symfony tutorials we have - Symfony 4 track :)

I hope this helps!

Cheers!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | victor | posted 2 years ago | edited

Hello victor,

Those are good links you gave. Yes, my project is Symfony 4, I will just focus on those Symfony 4 tutorials.

Thank you for your support!

Reply
Default user avatar
Default user avatar Michael Sypes | posted 4 years ago

Shouldn't the call to setOwner() have to occur before the persist()? If not, why?

Reply

Hey Michael!

That wasn't on purpose, but it makes for a great question :). The answer is: it doesn't matter (but it does need to be before flush). When you call persist(), it basically tells Doctrine: "Hey, be aware of this object. Later, if/when someone calls flush(), you should check out this object and save it to the database". Using persist doesn't put a "snapshot" of it in Doctrine at that time, it more just lets Doctrine know that it should be saved, once the time comes.

Cheers!

2 Reply
Default user avatar
Default user avatar Michael Sypes | weaverryan | posted 4 years ago

Thanks! That's a great explanation.

Reply
Max S. Avatar

in Symfony 2.8 I had to add
@ORM\JoinColumn(onDelete="SET NULL")
To the $owner variable.

Before a SQL error appeared:

[Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException]
An exception occurred while executing 'DELETE FROM yoda_user':
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or upda
te a parent row: a foreign key constraint fails (`symfony`.`yoda_event`, CO
NSTRAINT `FK_133826D97E3C61F9` FOREIGN KEY (`owner_id`) REFERENCES `yoda_us
er` (`id`))

Just in case someone else comes across this problem...

Reply

Yo Max!

This is a good find, and a pretty common - sometimes annoying "feature" in Doctrine. By default, all relationships have ON DELETE RESTRICT in the database: if you try to delete a User, but it is the "owner" of an Event... then you'll get this error. So, you have the right fix (well, that or "CASCADE"), as long as it fits your situation (I'd say, in this case, as long as knowing the $owner of an Event isn't mission critical, then this is cool. Otherwise, you might want CASCADE).

Cheers!

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.3.3",
        "symfony/symfony": "~2.4", // v2.4.2
        "doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
        "doctrine/doctrine-bundle": "~1.2", // v1.2.0
        "twig/extensions": "~1.0", // v1.0.1
        "symfony/assetic-bundle": "~2.3", // v2.3.0
        "symfony/swiftmailer-bundle": "~2.3", // v2.3.5
        "symfony/monolog-bundle": "~2.4", // v2.5.0
        "sensio/distribution-bundle": "~2.3", // v2.3.4
        "sensio/framework-extra-bundle": "~3.0", // v3.0.0
        "sensio/generator-bundle": "~2.3", // v2.3.4
        "incenteev/composer-parameter-handler": "~2.0", // v2.1.0
        "doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
        "ircmaxell/password-compat": "~1.0.3", // 1.0.3
        "phpunit/phpunit": "~4.1", // 4.1.0
        "stof/doctrine-extensions-bundle": "~1.1.0" // v1.1.0
    }
}