Login to bookmark this video
Buy Access to Course
03.

Saving a Relationship

Share this awesome video!

|

Keep on Learning!

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

Login Subscribe

Doctrine will create a genus_id integer column for this property and a foreign key to genus.

Use the "Code"->"Generate" menu to generate the getter and setter:

100 lines | src/AppBundle/Entity/GenusNote.php
// ... lines 1 - 10
class GenusNote
{
// ... lines 13 - 89
public function getGenus()
{
return $this->genus;
}
public function setGenus($genus)
{
$this->genus = $genus;
}
}

Add a Genus type-hint to setGenus():

100 lines | src/AppBundle/Entity/GenusNote.php
// ... lines 1 - 10
class GenusNote
{
// ... lines 13 - 94
public function setGenus(Genus $genus)
{
$this->genus = $genus;
}
}

Yes, when we call setGenus(), we'll pass it an entire Genus object not an ID. More on that soon.

Generate the Migration

Generate the migration for the change:

./bin/console doctrine:migrations:diff

And then go check it out... Wow - look at this!

// ... lines 1 - 10
class Version20160207091756 extends AbstractMigration
{
public function up(Schema $schema)
{
// ... lines 15 - 17
$this->addSql("ALTER TABLE genus_note ADD genus_id INT DEFAULT NULL");
$this->addSql("ALTER TABLE genus_note ADD CONSTRAINT FK_6478FCEC85C4074C FOREIGN KEY (genus_id) REFERENCES genus (id)");
$this->addSql("CREATE INDEX IDX_6478FCEC85C4074C ON genus_note (genus_id)");
}
// ... lines 22 - 31
}

Even though we called the property genus, it sets up the database exactly how you would have normally: with a genus_id integer column and a foreign key. And we did this with basically 2 lines of code.

Run the migration to celebrate!

./bin/console doctrine:migrations:migrate

Now, how do we actually save this relationship?

Saving a Relation

Head back to GenusController. In newAction(), create a new GenusNote - let's see how we can relate this to a Genus:

// ... lines 1 - 12
class GenusController extends Controller
{
// ... lines 15 - 17
public function newAction()
{
$genus = new Genus();
$genus->setName('Octopus'.rand(1, 100));
$genus->setSubFamily('Octopodinae');
$genus->setSpeciesCount(rand(100, 99999));
$note = new GenusNote();
// ... lines 26 - 37
}
// ... lines 39 - 107
}

I'll paste in some code here to set each of the normal properties - they're all required in the database right now:

// ... lines 1 - 24
$note = new GenusNote();
$note->setUsername('AquaWeaver');
$note->setUserAvatarFilename('ryan.jpeg');
$note->setNote('I counted 8 legs... as they wrapped around me');
$note->setCreatedAt(new \DateTime('-1 month'));
// ... lines 30 - 109

So how can we link this GenusNote to this Genus? Simple: $note->setGenus() and pass it the entire $genus object:

// ... lines 1 - 24
$note = new GenusNote();
$note->setUsername('AquaWeaver');
$note->setUserAvatarFilename('ryan.jpeg');
$note->setNote('I counted 8 legs... as they wrapped around me');
$note->setCreatedAt(new \DateTime('-1 month'));
$note->setGenus($genus);
// ... lines 31 - 109

That's it. Seriously! The only tricky part is that you set the entire object, not the ID. With Doctrine relations, you almost need to forget about ID's entirely: your job is to link one object to another. When you save, Doctrine works out the details of how this should look in the database.

Don't forget to persist the $note:

// ... lines 1 - 12
class GenusController extends Controller
{
// ... lines 15 - 17
public function newAction()
{
// ... lines 20 - 32
$em->persist($genus);
$em->persist($note);
$em->flush();
// ... lines 36 - 37
}
// ... lines 39 - 107
}

And, you can persist in any order: Doctrine automatically knows that it needs to insert the genus first and then the genus_note. That's really powerful.

Defaulting the isPublished Field

And simple! Head to the browser to check it out - /genus/new. Whoops - an error: the is_published property cannot be null. My bad - that's totally unrelated.

In Genus, give the $isPublished field a default value of true:

95 lines | src/AppBundle/Entity/Genus.php
// ... lines 1 - 10
class Genus
{
// ... lines 13 - 39
/**
* @ORM\Column(type="boolean")
*/
private $isPublished = true;
// ... lines 44 - 93
}

Now, if you forget to set this field - it'll default to true instead of null.

Woo! No errors this time. Check out the queries for the page. Nice! Two insert queries: INSERT INTO genus and then INSERT INTO genus_note using 46: the new genus's ID.

With two lines to setup the relationship, and one line to link a GenusNote to a Genus, you've got a fantastic new relationship.