Buy Access to Course
07.

Entities, Twig and the Magic dot Syntax

Share this awesome video!

|

Keep on Learning!

Let's finally make this page real with a template. Return $this->render('genus/list.html.twig') and pass it a genuses variable:

// ... lines 1 - 11
class GenusController extends Controller
{
// ... lines 14 - 33
public function listAction()
{
$em = $this->getDoctrine()->getManager();
$genuses = $em->getRepository('AppBundle:Genus')
->findAll();
return $this->render('genus/list.html.twig', [
'genuses' => $genuses
]);
}
// ... lines 45 - 89
}

You know what to do from here: in app/Resources/views/genus, create the new list.html.twig template. Don't forget to extend base.html.twig and then override the body block. I'll paste a table below to get us started:

18 lines | app/Resources/views/genus/list.html.twig
{% extends 'base.html.twig' %}
{% block body %}
<table class="table table-striped">
<thead>
<tr>
<th>Genus</th>
<th># of species</th>
</tr>
</thead>
<tbody>
// ... lines 12 - 14
</tbody>
</table>
{% endblock %}

Since genuses is an array, loop over it with {% for genus in genuses %} and add the {% endfor %}. Next, just dump out genus inside:

18 lines | app/Resources/views/genus/list.html.twig
// ... lines 1 - 10
<tbody>
{% for genus in genuses %}
{{ dump(genus) }}
{% endfor %}
</tbody>
// ... lines 16 - 18

Looks like a good start - try it out!. Ok cool - this dumps out 4 Genus objects. Open up the tr. Bring this to life with a td that prints {{ genus.name }} and another that prints {{ genus.speciesCount }}. And hey, we're getting autocompletion, that's kind of nice:

21 lines | app/Resources/views/genus/list.html.twig
// ... lines 1 - 10
<tbody>
{% for genus in genuses %}
<tr>
<td>{{ genus.name }}</td>
<td>{{ genus.speciesCount }}</td>
</tr>
{% endfor %}
</tbody>
// ... lines 19 - 21

The Magic Twig "." Notation

Refresh! Easy - it looks exactly how we want it. But wait a second... something cool just happened in the background. We printed genus.name... but name is a private property - so we should not be able to access it directly. How is this working?

81 lines | src/AppBundle/Entity/Genus.php
// ... lines 1 - 10
class Genus
{
// ... lines 13 - 22
private $name;
// ... lines 24 - 39
public function getName()
{
return $this->name;
}
// ... lines 44 - 79
}

This is Twig to the rescue! Behind the scenes, Twig noticed that name was private and called getName() instead. And it does the same thing with genus.speciesCount:

81 lines | src/AppBundle/Entity/Genus.php
// ... lines 1 - 10
class Genus
{
// ... lines 13 - 32
private $speciesCount;
// ... lines 34 - 59
public function getSpeciesCount()
{
return $this->speciesCount;
}
// ... lines 64 - 79
}

Twig is smart enough to figure out how to access the data - and this lets us keep the template simple.

With that in mind, I have a challenge! Add a third column to the table called "Last Updated":

23 lines | app/Resources/views/genus/list.html.twig
// ... lines 1 - 4
<thead>
<tr>
<th>Genus</th>
<th># of species</th>
<th>Last updated</th>
</tr>
</thead>
// ... lines 12 - 23

This won't work yet, but what I I want to be able to say is {{ genus.updatedAt }}. If this existed and returned a DateTime object, we could pipe it through the built-in Twig date filter to format it:

23 lines | app/Resources/views/genus/list.html.twig
// ... lines 1 - 11
<tbody>
{% for genus in genuses %}
<tr>
<td>{{ genus.name }}</td>
<td>{{ genus.speciesCount }}</td>
<td>{{ genus.updatedAt|date('Y-m-d') }}</td>
</tr>
{% endfor %}
</tbody>
// ... lines 21 - 23

But this won't work - there is not an updatedAt property. We'll add one later, but we're stuck right now.

Wait! We can fake it! Add a public function getUpdatedAt() and return a random DateTime object:

85 lines | src/AppBundle/Entity/Genus.php
// ... lines 1 - 10
class Genus
{
// ... lines 13 - 79
public function getUpdatedAt()
{
return new \DateTime('-'.rand(0, 100).' days');
}
}

Try that out. It works! Twig doesn't care that there is no updatedAt property - it happily calls the getter function. Twig, you're awesome.