Custom Alice Faker Function
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.
The Faker name()
function gives us a poor genus name. Yea, I know - this is just
fake data - but it's so wrong that it fails at its one job: to give us some
somewhat realistic data to make development easy.
Here's our goal: use a new <genus()>
function in Alice and have this return the
name of a random ocean-bound genus:
AppBundle\Entity\Genus: | |
genus_{1..10}: | |
name: <genus()> | |
// ... lines 4 - 7 |
This shouldn't work yet - but try it to see the error:
./bin/console doctrine:fixtures:load
Unknown formatter "genus"
Faker calls these functions "formatters". Can we create our own formatter? Absolutely.
Adding a Custom Formatter (Function)
In LoadFixtures
, break the load()
call onto multiple lines to keep things short
and civilized. Now, add a third argument - it's sort of an "options" array. Give
it a key called providers
- these will be additional objects that provide formatter
functions - and set it to an array with $this
:
// ... lines 1 - 9 | |
class LoadFixtures implements FixtureInterface | |
{ | |
public function load(ObjectManager $manager) | |
{ | |
$objects = Fixtures::load( | |
__DIR__.'/fixtures.yml', | |
$manager, | |
[ | |
'providers' => [$this] | |
] | |
); | |
} | |
// ... lines 22 - 45 | |
} |
And we're nearly done! To add a new genus
formatter, add public function genus()
.
I've already prepared a lovely list of some fantastic genuses that live in the ocean:
// ... lines 1 - 9 | |
class LoadFixtures implements FixtureInterface | |
{ | |
// ... lines 12 - 22 | |
public function genus() | |
{ | |
$genera = [ | |
'Octopus', | |
'Balaena', | |
'Orcinus', | |
'Hippocampus', | |
'Asterias', | |
'Amphiprion', | |
'Carcharodon', | |
'Aurelia', | |
'Cucumaria', | |
'Balistoides', | |
'Paralithodes', | |
'Chelonia', | |
'Trichechus', | |
'Eumetopias' | |
]; | |
// ... lines 41 - 44 | |
} | |
} |
Finish this with $key = array_rand($genera)
and then return $genera[$key]
:
// ... lines 1 - 9 | |
class LoadFixtures implements FixtureInterface | |
{ | |
// ... lines 12 - 22 | |
public function genus() | |
{ | |
// ... lines 25 - 41 | |
$key = array_rand($genera); | |
return $genera[$key]; | |
} | |
} |
Let's give it a try:
./bin/console doctrine:fixtures:load
No errors! Refresh! Ah, so much better.
New Random Boolean Column
Now, hold on, we have a new requirement: we need the ability to have published and unpublished genuses - for those times when we create a new genus, but we're still trying to think of a fun fact before it shows up on the site. With our beautiful migration and fixtures systems, this will be a breeze.
First, open Genus
and add a new private property
- call it $isPublished
. Next,
use the "Code"->"Generate" shortcut - or Ctrl
+Enter
- to generate the annotations:
// ... lines 1 - 10 | |
class Genus | |
{ | |
// ... lines 13 - 39 | |
/** | |
* @ORM\Column(type="boolean") | |
*/ | |
private $isPublished = true; | |
// ... lines 44 - 89 | |
public function setIsPublished($isPublished) | |
{ | |
$this->isPublished = $isPublished; | |
} | |
} |
Hey that was cool! Because the property started with is
, PhpStorm correctly guessed
that this is a boolean
column. Go team!
At the bottom, generate just the setter function. We can add a getter function later... if we need one.
We need to update the fixtures. But first, find the command line and generate the migration:
./bin/console doctrine:migrations:diff
Be a responsible dev and make sure the migration looks right:
// ... lines 1 - 10 | |
class Version20160207083347 extends AbstractMigration | |
{ | |
/** | |
* @param Schema $schema | |
*/ | |
public function up(Schema $schema) | |
{ | |
// this up() migration is auto-generated, please modify it to your needs | |
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); | |
$this->addSql('ALTER TABLE genus ADD is_published TINYINT(1) NOT NULL'); | |
} | |
/** | |
* @param Schema $schema | |
*/ | |
public function down(Schema $schema) | |
{ | |
// this down() migration is auto-generated, please modify it to your needs | |
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); | |
$this->addSql('ALTER TABLE genus DROP is_published'); | |
} | |
} |
Actually, it looks perfect. Run it:
./bin/console doctrine:migrations:migrate
Last step: we want to have a few unpublished genuses in the random data set. Open
the Faker documentation and search for "boolean". Perfect! There's a built-in boolean()
function and we can control the $chanceOfGettingTrue
. In the fixtures file,
add isPublished
and set that to boolean(75)
- so that most genuses are published:
AppBundle\Entity\Genus: | |
genus_{1..10}: | |
// ... lines 3 - 6 | |
isPublished: <boolean(75)> |
Re-run the fixtures!
./bin/console doctrine:fixtures:load
Hey, no errors! Now, to only show the published genuses on the list page, we need a custom query.
hey mate. Thanks alot for this video series, its really great! during the very last step after i add the private $isPublished colums, i add the setter public function setIsPublished($isPublished). wehn i run the php bin/console doctrine:fixtures:load command i get the following error.
PS D:\xampp\htdocs\aqua_note> 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
[Doctrine\DBAL\Exception\NotNullConstraintViolationException]
An exception occurred while executing 'INSERT INTO genus (name, sub_family, species_count, fun_fact, is_published)
VALUES (?, ?, ?, ?, ?)' with params [null, "Culpa consequatur.", 93263, "Accusamus nihil repellat vero omnis volupt
ates id amet et.", 1]:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null
[PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null
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>
why does is it trying to make name null at all, we only added that nullable=true stipulation to the $funFact column
also it did not do this until i added the isPublished column, before that it worked fine