If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
Now things are about to get fun. A few minutes ago, we installed a library called nelmio/alice - search for that and find their GitHub page.
In a nutshell, this library lets us add fixtures data via YAML files. It has an expressive syntax and it ships with a bunch of built-in functions for generating random data. Actually, it uses yet another library behind the scenes called Faker to do that. It's the PHP circle of life!
Find the ORM directory and create a new file called - how about fixtures.yml
. That
filename lacks excitement, but at least it's clear.
Start with the class name you want to create - AppBundle\Entity\Genus
. Next, each
genus needs an internal, unique name - it could be anything. But wait! Finish the
name with 1..10
:
AppBundle\Entity\Genus: | |
genus_{1..10}: | |
... lines 3 - 7 |
With this syntax, Alice will loop over and create 10 Genus objects for free. Boom!
To finish things, set values on each of the Genus properties: name: <name()>
. You
could just put any value here, but when using <>
, you're calling a built-in Faker
function. Next, use subFamily: <text(20)>
to generate 20 characters of random text,
speciesCount: <numberBetween(100, 100000)>
and funFact: <sentence()>
:
AppBundle\Entity\Genus: | |
genus_{1..10}: | |
name: <name()> | |
subFamily: <text(20)> | |
speciesCount: <numberBetween(100, 100000)> | |
funFact: <sentence()> |
That's it team! To load this file, open up LoadFixtures
and remove all of that
boring garbage. Replace it with Fixtures
- autocomplete that to get the use
statement -
then ::load()
. Pass this __DIR__.'/fixtures.yml'
and then the entity manager:
... lines 1 - 7 | |
use Nelmio\Alice\Fixtures; | |
class LoadFixtures implements FixtureInterface | |
{ | |
public function load(ObjectManager $manager) | |
{ | |
$objects = Fixtures::load(__DIR__.'/fixtures.yml', $manager); | |
} | |
} |
Now, run the exact command as before:
./bin/console doctrine:fixtures:load
I love when there are no errors. Refresh the list page. Voila: 10 completely random genuses. I love Alice.
Well.... the genus name is actually the name of a person... which is pretty ridiculous. Let's fix that in a second.
But first, Nelmio's documentation has a ton of cool examples of things you can
do with this library. But the biggest things you'll want to check out is the Faker
library that this integrates. This shows you all of the built-in functions we
were just using - like numberBetween
, word
, sentence
and a ton more. There
is some great stuff in here.
Now if we can just make the genus name a little more realistic.
Hey Danilo Silva
Yeah, you are right!
Alice has changed a lot in its newer version and it contains many BC breaks. We will discuss about it, so we can deliver a nice solution :)
Cheers!
Yep, we're already working on a few video notes so that people will know to use the older version for now :). The 3.0 release was just about a week or two ago... so the problem just started showing up!
if you don't want to always get the same generated data, set the seed to null when loading the fixtures:
Fixtures::load(
__DIR__ . '/fixtures.yml',
$manager,
[
'providers' => [$this],
'seed' => null
]
);
Hey Scott,
Thanks for sharing it with us! Here's a link to the docs with a bit more description about seeding the Faker's generator: https://github.com/fzaninot...
Cheers!
cool thanks. I was pulling my hair wondering why I kept getting the same data then it clicked, I shouldn't do these things too late at night :p
Hi,
Looks like Alice has been updated to 3.0 and the Fixtures
class no longer exists. So instead of that I used the NativeLoader
class.
use Nelmio\Alice\Loader\NativeLoader;```
And then in my `load()` function:
$loader = new NativeLoader();
$objectSet = $loader->loadFile(DIR.'/fixtures.yml')->getObjects();
foreach($objectSet as $object) {
$manager->persist($object);
$manager->flush();
}
Xdebug tells me that the `loadFile` function returns an array with one of the values being an array of all our objects. The `getObjects()` function gives us a nice array of all our objects. I wonder if there's a way to persist more than one object at a time but for now the for loop seems to work OK with our small data collection.
I also noticed that Alice 3.0 now comes with a Symfony Bundle and a service called `nelmio_alice.file_loader` but I couldn't figure out how to use that.
Hey Syed,
I think you can move flush() out of the foreach statement, so Doctrine will just persist() all the objects first and then flush() them at once.
Yes, you can register NelmioAliceBundle in your AppKernel and then configure it in app/config/config_dev.yml, check their docs for more information: https://github.com/nelmio/a... . Service "nelmio_alice.file_loader" has only one public method loadFile() where you need to pass path to the file you want to load. Then it will parse the file and load data by itself.
Cheers!
Hi Victor,
Thanks for the reply. Moving the flush() out of the foreach works great! I also had no idea (until reading the Symfony docs) https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html#using-the-container-in-the-fixtures that we had access to the container in our Fixtures class.
With that I was able to load the nelmio_alice.file_loader service and load the yml file that way. So my load function now becomes
$fileLoader = $this->container->get('nelmio_alice.file_loader');
$objectSet = $fileLoader->loadFile(__DIR__.'/fixtures.yml')->getObjects();
foreach($objectSet as $object) {
$manager->persist($object);
}
$manager->flush();```
Hi!
So, there are a lot of problems with the ./bin/console doctrine:fixtures:load command due to the Alice update. A programmer friend of mine found a solution that worked for me, and I'd like to share it for those who are still stuck on this.
Using composer in your terminal, make sure to install the nelmio/alice "2.1.4" version, and the doctrine-fixtures-bundle "2.3" version.
composer require --dev nelmio/alice "2.1.4"
composer require --dev doctrine/doctrine-fixtures-bundle "2.3"
If you already have nelmio/alice installed on a wrong version, you can go to composer.json and change the version to "2.1.4".
"nelmio/alice": "2.1.4",
In LoadFixtures.php, add these use statements and change your class LoadFixtures:
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Faker;
class LoadFixtures extends Fixture
{
public function load(ObjectManager $manager) {
$objects = Fixtures::load(
__DIR__.'/Fixtures.yml',
$manager,
[ 'providers' => [$this] ]
);
// $manager->persist($institution);
// $manager->flush();
}
}
In AppKernel.php, keep the Doctrine $bundle but remove the Nelmio $bundle in the if statement:
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
<strike>$bundles[] = new Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle();</strike>
Now, for me at least, ./bin/console doctrine:fixtures:load finally works.
Hopefully that helps someone else like it helped me!
Oh and by the way, great tutorial so far. Thanks for the energetic and fun teaching.
Hey Tom!
Bah, yea. First, thank you for sharing this! Second, I currently only recommend Alice if you use the *old* version. The setup for the new version looks crazy to me... and YAML fixtures should be fun and easy, not a technical challenge :).
Thanks again for sharing - very happy you're enjoying the tuts!
Hello, weaverryan!
What would you recommend for Alice replacement? I've just updated from 3.2 to 4.2 and does it mean that the fixtures system needs the complete rework?
Hey Andrei V. ,
For Symfony 4 we recommend using DoctrineFixturesBundle along with Faker library, we even have a related screencasts for it in our Symfony 4 series, you can check it here: https://symfonycasts.com/sc... .
Cheers!
victor, thanks, Victor! I've already seen that and it looks awesome but not as awesome as Alice was. It was just an attempt to find something yml-like)
Hey Andrei V. ,
Ah, I see... Then just use the same hautelook/AliceBundle but follow the docs for the 2nd version of it. That's still the best probably with active support :)
Cheers!
victor, I've already rewritten my fixtures for standard Doctrine Fixtures. It wasn't as hard as I thought it would) Thanks for your help!
Hey Andrei V. ,
Ah, OK! :) Fairly speaking, doing fixtures in PHP is even more fun, at least for me, since I can get IDE autocompletion, etc and these fixtures are more flexible than Yaml one :p You can easily complicate them, not always possible that easy with Alice.
Cheers!
Hello,
I'm seeking for best practice advises on using alicebundle for functional tests.
As long as I don't add new fields to populate, everything is okay. Each generation run produce same data, so tests doesn't break.
As soon as I add a new field to populate, every subsequent generated datas change. So test break.
Is there a way to avoid this ?
Hey Fenring,
I personally don't use AliceBundle in my unit tests, could you look at this thread, maybe this will help to fix your problem: https://knpuniversity.com/s... . But I think a better practice is do not use AliceBundle in tests and instead boot Symfony kernel and set only that data you need before running each test - PHPUnit helps with it well.
Cheers!
Hi, I clone a project where I'm going to start working and when doing a composer install I had this error ...
PHP Parse error: syntax error, unexpected '.', expecting ',' or ';' in /var/www/html/proyectos/lcdmp-api/vendor/nelmio/alice/src/Nelmio/Alice/Instances/Processor/Methods/Reference.php on line 20
Hey Felipe Javier Viñoles
It may be related to your PHP version, but I'm not 100% sure, which version are you using ?
Which version of nelmio-alice are you trying to install ? also make sure that your composer is updated
Cheers!
So you could run "composer install" after installing PHP 7 and everything ran fine ? or you got that error after PHP installation ?
Hi,
Just in case someone else is running into this issue :
I am running symfony and the database in two separate Docker containers.
I created those containers myself and they are based on alpine linux.
Since Alpine does not support GLOB_BRACE
(The thing is that Alpine Linux uses musl-libc instead of the Linux standard GNU libc. It seems that musl does not implement GLOB_BRACE because this is not a POSIX defined option.)
I got an error when executing the bin/console doctrine:fixtures:load
[Symfony\Component\Debug\Exception\ContextErrorException]
Notice: Use of undefined constant GLOB_BRACE - assumed 'GLOB_BRACE'
As long as Alpine has this limitation, the following workaround can be used :
Edit vendor/nelmio/alice/src/Nelmio/Alice/Fixtures.php
and replace the line
$matches = glob($files, GLOB_BRACE);
with
$matches = glob($files, (defined('GLOB_BRACE') ? GLOB_BRACE : 0));
After this change the fixtures run smoothly
Hey Hans!
Wow, you should totally submit this as a pull request to Alice - it's a great bug fix! Either way, thanks for posting here!
Hey Stan,
Probably you could do something similar if you have access to the Symfony service container from your unit tests, but anyway, I do *not* think it's a good idea. Usually, all actual values are hardcoded in tests, which make tests more robust. Actually, if you change your fixtures - it's normal behavior if your tests fails. Because this way you will able to catch this change if you made it unintentionally. But if you do such kind of dependency - you won't be aware about it. So better do hardcode values in your tests ;)
Cheers!
Hi,
I would like to load two types of data fixtures: fake data and "true" data.
I have written this:
AppBundle\Entity\Groupe:
grab:
nom: Grab
rotation:
nom: Rotation
flip:
nom: Flip
slide:
nom: Slide
old_school:
nom: Old school
AppBundle\Entity\Snowtricks:
-
nom: "Spin 180"
groupe: '@groupe_*'
contenu: <text(500)>
photo: "images/figure1.jpg"
video_url: "https://www.youtube.com/embed/Dlj0nIUvypw?list=PLA19FB9E97B041212"
is_commented: <boolean(75)>
When I try to load the fixtures I get an error :
Instance mask "groupe_*" did not match any existing instance, make sure the object is created after its references
I think I don't understand the error message. Could you please explain it to me ?
Thank you.
Hi Carmen Fabo!
I think I know the problem :). When you reference @group_*
, this references the keys you're using in your file - e.g. grab
, rotation
, etc. You should update the keys under your Groupe entity to all start with the same prefix. For example:
AppBundle\Entity\Groupe:
groupe_grab:
nom: Grab
groupe_rotation:
nom: Rotation
# ...
I hope that helps! Cheers!
Thank you very much ! that helps me to understand how it works. I get another error, I look for a solution.
Cheers !
Hello, I am trying to use the fixtures with Alice, and I got the following message in the Terminal :
php bin/console doctrine:fixtures:load
Careful, database will be purged. Do you want to continue y/N ?y
> purging database
> loading AppBundle\DataFixtures\ORM\LoadFixtures
Parse error: parse error, expecting `','' or `';'' in /Users/me/vendor/nelmio/alice/src/Nelmio/Alice/Instances/Processor/Methods/Reference.php on line 20
[Symfony\Component\Debug\Exception\FatalErrorException]
Parse Error: parse error, expecting `','' or `';''
doctrine:fixtures:load [--fixtures [FIXTURES]] [--append] [--em EM] [--shard SHARD] [--purge-with-truncate] [--multiple-transactions] [-h|--help] [-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi] [--no-ansi] [-n|--no-interaction] [-e|--env ENV] [--no-debug] [--] <command>
Hey Stephane,
It seems you have syntax error in your fixtures: you missed `,` or `;` somewhere, but it difficult to say where - I don't see your code. Please, double check code of your fixtures. With PHP files PhpStorm helps well, but with YAML most probably you should do it manually. Btw, is it a public project? Could you show me content of your fixture?
Cheers!
Hello Victor,
It's the current tutorial. Here is the YAML file fixtures.yml :
AppBundle\Entity\Genus:
genus_{1..10}:
name: <name()>
subFamily: <text(20)>
speciesCount: <numberBetween(100, 100000)>
funFact: <sentence()>
And the LoadFixtures.php file :
namespace AppBundle\DataFixtures\ORM;
use AppBundle\Entity\Genus;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Nelmio\Alice\Fixtures;
class LoadFixtures implements FixtureInterface
{
public function load(ObjectManager $manager)
{
Fixtures::load(__DIR__.'/fixtures.yml', $manager);
}
}
Sorry, the indentation does not display.
Stephane
Hey Stephane,
As I see you have unexpected =""
symbol in numberbetween()
function, please, remove it. I bet it's the problem, the right line should be:
AppBundle\Entity\Genus:
genus_{1..10}:
speciesCount: <numberBetween(100, 100000)>
and btw, consider a correct letter case: numberBetween()
not numberbetween()
;)
P.S. I tweak styles in your message a bit to improve code readability: use pre and code tags for formatting, or take a look at GitHub's Gist service.
Cheers!
Hi Victor,
I have checked my code, and there is no syntax error like you describe. Maybe the typo in my post above comes from when I paste the code in my message and when trying to indent the code.
It still does not work.
This is what I found in Reference.php file :
private static $regex = '/^[\',\"]?'
.'(?:(?<multi>\d+)x\ )?'
.'@(?<reference>[\p{L}\d\_\.\*\/\-]+)'
.'(?<sequence>\{(?P<from>\d+)\.\.(?P<to>\d+)\})?'
.'(?:\->(?<property>[\p{L}\d_.*\/-]+))?'
.'[\',\"]?$'
.'/xi';
Line 20 is the line just below private static. So I suspect there is a bug in the regex ?
Stephane
Hi Stephane!
Hmm, yes, this is very strange - it almost seems like that line 20 has a syntax error in the PHP file itself, which definitely doesn't make any sense (I've checked on the alice repository, and I don't see any reports of a similar error). Just in case there was some sort of corruption when downloading alice, try this:
rm -rf vendor/
composer install
Also, what version of PHP are you on?
Cheers!
Hello Ryan,
I tried your instructions but still having the error message.
I also tried to copy the finish version of the two files fixtures.yml and LoadFixtures.php from the source code directory.
Maybe it's a php version conflict.
I am using MAMP PRO v4.0.5 on OS X El Capitan. I have setup MAMP Pro and Apache to use PHP 5.6.25. I think I have properly setup PHP Storm to use MAMP Pro PHP version.
I even tried to manually install PHP 5.6.25 on my Mac to override the former php installation. But when I open a terminal window and type PHP -v, the version is 5.5.36.
Good news Ryan and Victor.
I have started again Course 3 from the beginning, with a clean start code.
Now, I don't have errors anymore with Nelmio/Alice.
So now I can continue the course.
I don't know where the error was.
Stephane
Hey Stephane!
This type of error is *really* weird - great job on thinking to start from scratch to fix it! Sometimes, you can even get weird things in files like hidden whitespace characters that can cause problems. This is pretty rare, but I can remember a few times when I've had something weird like this and have pulled my hair out debugging it.
Onward from here! Cheers!
In order to get this to work I had to add:
AppBundle\DataFixtures\ORM\LoadFixtures:
tags: [doctrine.fixture.orm]
In services.yml
Hey Jack,
Thanks for sharing your solution! Yes, looks like it's required for DoctrineFixturesBundle. But If you're using the default service configuration, any class that implements ORMFixtureInterface will automatically be registered with this tag, see https://symfony.com/doc/mas... for more information.
Cheers!
When I namespace with ORM, PhpStorm yells at me with the error message "Undefined constant ORM" and "Expected identifier". And it'll refuse to recognize the use statements, causing the implements FixtureInterface to be unrecognized. Once I remove the ORM from the namespace, PhpStorm is happy and I get my autocomplete. My question is why and what can I do to fix it?
Hey 0x90 ,
Could you provide a bit more information? What version of PhpStorm do you use? Do you have the "PHP Annotations" plugin installed for PhpStorm? And please, show the part of your entity when you get this error (Show us how you use this namespace and some property where you try to use it and get error). We would be happy to help you with it. Thanks!
Cheers!
Certainly.
- I have the 2016.1 (most recently patched) version of PhpStorm and IntelliJ IDEA on two different machines
- Both have PHP Annotations and Symfony
Here's the screenshot with ORM in the namespace:
Here's the screenshot without ORM in the namespace:
$ pwd;ls
/[...]/src/AppBundle/DataFixtures/ORM
LoadFixtures.php fixtures_blog.yml fixtures_projects.yml
I think I've seen this before actually - it's a bug in PhpStorm itself. Sometimes, for some reason, it suddenly thinks that a namespace has a syntax error in it. I copy the entire namepace line, delete it, wait a moment, then paste it back. For me, PhpStorm is happy once I do this.
Let me know if this works!
Hey Chmlls,
I suppose you didn't set the correct locale in Alice bundle config. Set the alice locale to "es_ES" in your config file:
# app/config/config_dev.yml
hautelook_alice:
locale: es_ES
Let me know if it helped.
Cheers!
I just can't get Alice to work! :(
I'm not even sure which package to install now: nelmio/alice or hautelook/alice-bundle
The way shown in the video doesn't work for me -- the class Nelmio\Alice\Fixtures seems like doesn't exist anymore.
And I can't get hautelook/alice-bundle to work either... Seems like they don't support Symfony 3... For example, their documentation suggests using "php app/console fixtures:load"
Well, I did get to work nelmio/alice 3.0.dev and (after that) hautelook/alice-bundle (via AbstractLoader::getFixtures() method).
But after running doctrine:fixtures:load the database remained empty...
OMG, a couple of hours of frustration and now I've found the solution myself... I just had to use hautelook_alice:doctrine:fixtures:load
Ok, maybe this will be helpful to somebody, so the steps are:
1) composer require --dev hautelook/alice-bundle doctrine/data-fixtures
2) activate it in the AppKernel:
$bundles[] = new Hautelook\AliceBundle\HautelookAliceBundle();
3) create an yml file in the src/AppBundle/DataFixtures/ORM folder (we don't need any additional classes there)
4) ./bin/console hautelook_alice:doctrine:fixtures:load
Additionally, configure the bundle in the config_dev.yml
P.S. And locale setting doesn't work for me for some reason. I set
hautelook_alice:
locale: ru
but to no effect.
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.1.*", // v3.1.4
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.6.4
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.3.11
"symfony/monolog-bundle": "^2.8", // 2.11.1
"symfony/polyfill-apcu": "^1.0", // v1.2.0
"sensio/distribution-bundle": "^5.0", // v5.0.22
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
"doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.0.7
"symfony/phpunit-bridge": "^3.0", // v3.1.3
"nelmio/alice": "^2.1", // 2.1.4
"doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
}
}
I got an not found exception when running doctrine:fixture:load. The problem was due to an incompatible Nelmio\Alice version. From the previous video, I needed to install Alice specifying the version: 2.1.4 with
`
composer require --dev nelmio/alice:2.1.4
`
and them worked. Maybe we need a video update?